diff --git a/.github/workflows/build-on-push.yml b/.github/workflows/build-on-push.yml index 9720316dd2..c1409c50b1 100644 --- a/.github/workflows/build-on-push.yml +++ b/.github/workflows/build-on-push.yml @@ -7,59 +7,37 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - postgresql: ['9.6','14'] - services: - postgres: - image: postgres:${{ matrix.postgresql }} - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres - ports: - - 5432:5432 - # needed because the postgres container does not provide a healthcheck - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + postgresql: ['10','15'] steps: - - uses: actions/checkout@v1 - - uses: actions/cache@v1 + - uses: actions/checkout@v3 + - uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradlew') }} restore-keys: | ${{ runner.os }}-gradlew- - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: - java-version: 11 - - name: Set up DB - run: | - sudo apt-get install --yes postgresql-client - psql -h 127.0.0.1 -U postgres postgres -c 'create database alfio;' -f src/test/resources/init-db-user.sql - env: - PGPASSWORD: postgres + java-version: 17 + distribution: temurin - name: Build with Gradle - run: ./gradlew build distribution jacocoTestReport -Dspring.profiles.active=travis -Ddbenv=PGSQL-TRAVIS -Dpgsql${{ matrix.postgresql }} + run: ./gradlew dist jacocoTestReport -Dpgsql.version=${{ matrix.postgresql }} - name: upload to sonarcloud if: ${{ github.repository == 'alfio-event/alf.io' && matrix.postgresql == '14'}} run: ./gradlew sonarqube env: SONARCLOUD_TOKEN: ${{ secrets.SONAR_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -# - name: upload-to-coveralls -# if: matrix.postgresql == '13' # run only once -# run: ./gradlew coveralls -# env: -# COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - name: 'Upload Build' - if: ${{ github.repository == 'alfio-event/alf.io' && matrix.postgresql == '9.6'}} - uses: actions/upload-artifact@v2 + if: ${{ github.repository == 'alfio-event/alf.io' && matrix.postgresql == '10'}} + uses: actions/upload-artifact@v3 with: name: dist path: build @@ -71,23 +49,26 @@ jobs: name: Push dev image steps: - name: Download artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: dist + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 - name: Configure Docker - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ secrets.CR_USER }} password: ${{ secrets.CR_PAT }} - name: Inject slug/short variables - uses: rlespinasse/github-slug-action@v3.x + uses: rlespinasse/github-slug-action@v4.4.1 - name: Push Docker image - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: ./dockerize tags: | ghcr.io/alfio-event/alf.io/dev-${{ env.GITHUB_REF_SLUG }}:latest + platforms: linux/amd64,linux/arm64 push: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0e0dee3c6c..39449df9d2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,28 +13,24 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: - java-version: 11 + java-version: 17 + distribution: temurin - name: Build with Gradle run: ./gradlew build -x test @@ -51,4 +47,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 5ed4d1caf0..d0e052cc25 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -9,26 +9,27 @@ jobs: if: github.repository == 'alfio-event/alf.io' strategy: matrix: - browser: ['chrome', 'firefox', 'safari', 'ie11'] + browser: ['chrome', 'firefox', 'safari'] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/cache@v1 + - uses: actions/checkout@v3 + - uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradlew') }} restore-keys: | ${{ runner.os }}-gradlew- - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: - java-version: 11 + java-version: 17 + distribution: temurin - name: 'BrowserStack Env Setup' uses: 'browserstack/github-actions/setup-env@master' with: diff --git a/.gitignore b/.gitignore index 0fda5edfaa..5274c4c67d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,6 @@ out/ alfio-itest .gradletasknamecache public/ +!frontend/projects/public node_modules/ lsp diff --git a/.sdkmanrc b/.sdkmanrc new file mode 100644 index 0000000000..077c04ba59 --- /dev/null +++ b/.sdkmanrc @@ -0,0 +1,3 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +java=17.0.3-zulu diff --git a/README.md b/README.md index d0ecd788e8..76f3f914b3 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,13 @@ The open source ticket reservation system. ## Warning As the work for Alf.io [v2](https://github.com/alfio-event/alf.io/milestones) has started, this branch may contain **unstable** and **untested** code. -If you want to build and deploy alf.io by yourself, we strongly suggest you to use the [2.0-M3-maintenance](https://github.com/alfio-event/alf.io/tree/2.0-M3-maintenance) branch, as it contains production-ready code. +If you want to build and deploy alf.io by yourself, we strongly suggest you to use the [2.0-M4-maintenance](https://github.com/alfio-event/alf.io/tree/2.0-M4-maintenance) branch, as it contains production-ready code. ## Prerequisites -You should have installed Java version **11** (e.g. [Oracle's](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [OpenJDK](http://openjdk.java.net/install/), or any other distribution) to build and run alf.io. Please note that for the build process the JDK is required. +You should have installed Java version **17** (e.g. [Oracle's](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [OpenJDK](http://openjdk.java.net/install/), or any other distribution) to build and run alf.io. Please note that for the build process the JDK is required. -Postgresql version 9.6 or later. +Postgresql version 10 or later. Additionally, the database user that creates and uses the tables should not be a "SUPERUSER", or else the row security policy checks will not be applied. @@ -46,7 +46,7 @@ You must specify a project property at the command line, such as ``` The local "bootRun" task has the following prerequisites: -- a PostgreSQL (version 9.6 or later) instance up and running on localhost:5432 +- a PostgreSQL (version 10 or later) instance up and running on localhost:5432 - a _postgres_ user having a password: _password_ - a database named _alfio_ @@ -153,10 +153,10 @@ However, if you decide to do so, then you need to make a couple of changes: docker build -t alfio/alf.io ./build/dockerize ``` -### About the included AppleWWDRCA.cer +### About the included AppleWWDRCAG4.cer -The certificate at src/main/resources/alfio/certificates/AppleWWDRCA.cer has been imported for https://github.com/ryantenney/passkit4j#usage functionality. -It will expire the 02/07/23 (as https://www.apple.com/certificateauthority/). +The certificate at src/main/resources/alfio/certificates/AppleWWDRCAG4.cer has been imported for https://github.com/ryantenney/passkit4j#usage functionality. +It will expire the 2030-10-12 (YYYY-MM-DD - as of https://www.apple.com/certificateauthority/). ## Available spring profiles: @@ -174,7 +174,7 @@ This project exists thanks to all the people who contribute. ### Translation Contributors (POEditor) -A big "Thank you" goes also to our translators, who help us on [POEditor](https://poeditor.com/join/project/ttBYTmPYdr): +A big "Thank you" goes also to our translators, who help us on [POEditor](https://github.com/alfio-event/alf.io/tree/master/src/main/resources/alfio/i18n): (we show the complete name/profile only if we have received explicit consent to do so) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..014995f902 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policy + +## Supported Versions + +We support the latest major release, which is at the moment **2.0-M4**. +In case of direct or transitive vulnerability in that code, we'll release a new version as soon as possible. +Please follow us on [Twitter](https://twitter.com/alfio_event) for release announcements, and keep your alf.io updated! + +| Version | Supported | +| ------- | ------------------ | +| 2.0-M4 | :white_check_mark: | +| 2.0-M3 | :x: | +| 2.0-M2 | :x: | +| 2.0-M1 | :x: | + +## Note about the master branch + +We consider the "master" branch to be always a "Work in Progress", and as such it might contain vulnerabilities. +Before each release we'll run an additional scan on [SonarCloud](https://sonarcloud.io/summary/overall?id=alfio-event_alf.io) and fix all the security-releated findings. +That branch should not be deployed in production. If you do that, you're on your own. + + +## Reporting a Vulnerability + +Please reach out via email to `security @ alf.io` (remove spaces), we'll reply as soon as possible. Thank you for sharing responsibly! diff --git a/build.gradle b/build.gradle index 3f8d227ba7..e5e0f6af5a 100644 --- a/build.gradle +++ b/build.gradle @@ -13,11 +13,9 @@ import java.time.format.DateTimeFormatter buildscript { dependencies { - classpath 'com.opentable.components:otj-pg-embedded:0.13.3' - classpath 'org.postgresql:postgresql:42.2.20' + classpath 'org.postgresql:postgresql:42.5.1' //this is for processing the index.html at compile time - classpath "com.github.alfio-event:alf.io-public-frontend:$alfioPublicFrontendVersion" - classpath "ch.digitalfondue.jfiveparse:jfiveparse:0.9.0" + classpath "ch.digitalfondue.jfiveparse:jfiveparse:1.0.0" // } @@ -26,24 +24,21 @@ buildscript { url "https://plugins.gradle.org/m2/" } mavenCentral() - maven { - url "https://jitpack.io" - } } } plugins { - id 'io.freefair.lombok' version '5.3.3.3' + id 'io.freefair.lombok' version '6.6.1' id 'java' id 'idea' - id 'org.kordamp.gradle.jacoco' version '0.45.0' - id 'com.github.ben-manes.versions' version '0.38.0' + id 'org.kordamp.gradle.jacoco' version '0.48.0' + id 'com.github.ben-manes.versions' version '0.44.0' id 'com.github.hierynomus.license' version '0.16.1' - id 'net.researchgate.release' version '2.8.1' - id 'org.springframework.boot' version '2.4.5' - id 'org.sonarqube' version '3.3' - id 'net.ltgt.errorprone' version '2.0.1' - id 'com.github.node-gradle.node' version '3.1.0' + id 'net.researchgate.release' version '3.0.2' + id 'org.springframework.boot' version '2.7.7' + id 'org.sonarqube' version '3.5.0.2730' + id 'net.ltgt.errorprone' version '2.0.2' + id 'com.github.node-gradle.node' version '3.5.1' } apply plugin: 'java' @@ -52,13 +47,17 @@ apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' apply plugin: 'project-report' +// MJML email templates translations to HTML +node { + download = true +} //as pointed out by @facundofarias, we should validate minimum javac version -task validate { +tasks.register('validate') { //check JDK version def javaVersion = JavaVersion.current() - if (!javaVersion.isJava11Compatible()) { - throw new GradleException("A Java JDK 11+ is required to build the project.") + if (!javaVersion.isCompatibleWith(JavaVersion.VERSION_17)) { + throw new GradleException("A Java JDK 17+ is required to build the project.") } } @@ -100,20 +99,17 @@ configurations { repositories { mavenLocal() mavenCentral() - maven { - url "https://jitpack.io" - } } dependencies { implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" - implementation 'com.auth0:java-jwt:3.18.2' + implementation 'com.auth0:java-jwt:4.2.1' implementation "com.fasterxml.jackson.core:jackson-core" implementation "com.fasterxml.jackson.core:jackson-databind" implementation "org.springframework.boot:spring-boot-properties-migrator", { exclude module : 'spring-boot-starter-logging' } - implementation 'org.springframework.session:spring-session:1.3.5.RELEASE' + implementation 'org.springframework.session:spring-session-jdbc' implementation "ch.digitalfondue.npjt-extra:npjt-extra:2.0.4" implementation "com.samskivert:jmustache:1.15" implementation "javax.mail:mail:1.5.0-b01" @@ -121,50 +117,48 @@ dependencies { /**/ implementation 'com.openhtmltopdf:openhtmltopdf-core:1.0.10' implementation 'com.openhtmltopdf:openhtmltopdf-pdfbox:1.0.10' - implementation "ch.digitalfondue.jfiveparse:jfiveparse:0.9.0" + implementation 'ch.digitalfondue.jfiveparse:jfiveparse:1.0.0' /**/ - implementation "com.google.zxing:core:3.4.1" - implementation "com.google.zxing:javase:3.4.1" + implementation 'com.google.zxing:core:3.5.1' + implementation 'com.google.zxing:javase:3.5.1' implementation "org.flywaydb:flyway-core" implementation "org.postgresql:postgresql" implementation "com.zaxxer:HikariCP" /* https://www.lunasec.io/docs/blog/log4j-zero-day/ */ - implementation "org.apache.logging.log4j:log4j-api:2.17.1" - implementation "org.apache.logging.log4j:log4j-core:2.17.1" - implementation "org.apache.logging.log4j:log4j-jul:2.17.1" - implementation "org.apache.logging.log4j:log4j-slf4j-impl:2.17.1" + implementation 'org.apache.logging.log4j:log4j-api:2.19.0' + implementation 'org.apache.logging.log4j:log4j-core:2.19.0' + implementation 'org.apache.logging.log4j:log4j-jul:2.19.0' + implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.19.0' /**/ - implementation "com.stripe:stripe-java:20.50.0" - implementation 'com.paypal.sdk:checkout-sdk:1.0.5' - implementation 'com.google.code.gson:gson:2.8.9' - implementation 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.1', { + implementation "com.stripe:stripe-java:22.4.0" + implementation 'com.paypal.sdk:checkout-sdk:2.0.0' + implementation 'com.google.code.gson:gson:2.10' + implementation 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2', { exclude module: 'gson' } implementation "org.apache.commons:commons-lang3:3.12.0" - implementation "org.apache.commons:commons-text:1.9" - implementation 'com.opencsv:opencsv:5.5.2' + implementation 'com.opencsv:opencsv:5.7.1' implementation 'commons-codec:commons-codec:1.15' implementation 'net.sf.biweekly:biweekly:0.6.6' implementation 'com.atlassian.commonmark:commonmark:0.17.0' implementation 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.17.0' implementation 'com.ryantenney.passkit4j:passkit4j:2.0.1' implementation 'com.github.ben-manes.caffeine:caffeine' - implementation 'com.github.scribejava:scribejava-core:5.0.0' + implementation 'com.github.scribejava:scribejava-core:8.3.3' implementation 'ch.digitalfondue.vatchecker:vatchecker:1.5.0' implementation 'ch.digitalfondue.basicxlsx:basicxlsx:0.5.1' implementation 'org.imgscalr:imgscalr-lib:4.2' implementation 'org.mozilla:rhino-runtime:1.7.13' - - implementation "com.github.alfio-event:alf.io-public-frontend:$alfioPublicFrontendVersion" + implementation 'com.google.auth:google-auth-library-oauth2-http:1.3.0' compileOnly "javax.servlet:javax.servlet-api:4.0.1" testImplementation "javax.servlet:javax.servlet-api:4.0.1" - testImplementation 'org.testcontainers:testcontainers:1.16.2' - testImplementation 'org.testcontainers:postgresql:1.16.2' - testImplementation 'org.testcontainers:junit-jupiter:1.16.2' + testImplementation 'org.testcontainers:testcontainers:1.17.6' + testImplementation 'org.testcontainers:postgresql:1.17.6' + testImplementation 'org.testcontainers:junit-jupiter:1.17.6' testImplementation "org.springframework.boot:spring-boot-starter-test", { exclude module : 'spring-boot-starter-logging' } @@ -197,6 +191,10 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api" testImplementation "org.junit.jupiter:junit-jupiter-engine" testImplementation "org.junit.platform:junit-platform-engine" + testImplementation "org.mockito:mockito-inline:4.5.1" + + testImplementation "org.springdoc:springdoc-openapi-ui:1.6.14" + testImplementation "org.openapitools.openapidiff:openapi-diff-core:2.0.1" providedCompile "org.springframework.boot:spring-boot-starter-jetty", { exclude group: "org.eclipse.jetty.websocket", module: "websocket-server" @@ -209,16 +207,16 @@ dependencies { exclude module : 'spring-boot-starter-logging' } - implementation "org.joda:joda-money:1.0.1" + implementation "org.joda:joda-money:1.0.3" - testImplementation 'org.mock-server:mockserver-netty:5.11.2', { + testImplementation 'org.mock-server:mockserver-netty:5.13.2', { exclude group: 'org.mozilla', module: 'rhino' } annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" - testImplementation 'org.seleniumhq.selenium:selenium-java:4.1.1' + testImplementation 'org.seleniumhq.selenium:selenium-java:4.7.2' - errorprone('com.google.errorprone:error_prone_core:2.4.0') + errorprone('com.google.errorprone:error_prone_core:2.10.0') } // -- license configuration @@ -258,30 +256,7 @@ processResources { gradleProperties.withReader { properties.load(it) } properties['alfio.version'] = project.version properties['alfio.build-ts'] = ZonedDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ISO_ZONED_DATE_TIME) - properties['alfio.frontend.version'] = alfioPublicFrontendVersion gradleProperties.withWriter { properties.store(it, null) } - - - // - // alf.io public frontend: read index.html rewrite path for css/js - - final resource = Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/resources/webjars/alfio-public-frontend/$alfioPublicFrontendVersion/alfio-public-frontend/index.html") - final indexDoc = new Parser().parse(new InputStreamReader(resource, StandardCharsets.UTF_8)) - - final basePath = "webjars/alfio-public-frontend/$alfioPublicFrontendVersion/alfio-public-frontend/" - NodeMatcher scriptNodes = Selector.select().element("script").toMatcher() - - indexDoc.getAllNodesMatching(scriptNodes).stream().forEach({ - it.setAttribute("src", basePath + it.getAttribute("src")) - }) - - NodeMatcher cssNodes = Selector.select().element("link").attrValEq("rel", "stylesheet").toMatcher(); - indexDoc.getAllNodesMatching(cssNodes).stream().forEach({ - it.setAttribute("href", basePath + it.getAttribute("href")) - }) - - final alfioPublicIndex = new File((File) it.destinationDir, "alfio-public-frontend-index.html") - alfioPublicIndex.write(HtmlSerializer.serialize(indexDoc), "UTF-8", false) } } @@ -293,7 +268,8 @@ compileTestJava { 'AlmostJavadoc', 'MissingSummary', 'EscapedEntity', - 'EmptyBlockTag' + 'EmptyBlockTag', + 'SameNameButDifferent' ) } @@ -308,7 +284,9 @@ compileJava { 'AlmostJavadoc', 'MissingSummary', 'EscapedEntity', - 'EmptyBlockTag' + 'EmptyBlockTag', + 'SameNameButDifferent', + 'ReturnValueIgnored' ) } @@ -319,7 +297,6 @@ test { useJUnitPlatform() systemProperties = System.properties systemProperties.remove("java.endorsed.dirs") - jvmArgs("--illegal-access=warn") testLogging { events "failed" exceptionFormat "full" @@ -327,6 +304,9 @@ test { } } +springBoot { + mainClass = 'alfio.config.SpringBootLauncher' +} bootRun { def externalConfig = new File("./custom.jvmargs") @@ -337,33 +317,16 @@ bootRun { "-Ddatasource.username=${project.datasourceUsername}", "-Ddatasource.password=${project.datasourcePassword}", "-Dalfio.version=${project.version}", - "-Dalfio.build-ts=${ZonedDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}", - "-Dalfio.frontend.version=$alfioPublicFrontendVersion" + "-Dalfio.build-ts=${ZonedDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}" ] if(externalConfig.exists()) { opts += externalConfig.readLines() } jvmArgs = opts - mainClass = 'alfio.config.SpringBootLauncher' -} - -bootWar { - mainClassName = 'alfio.config.SpringBootLauncher' - classifier = 'boot' - - def bowerDir = "resources/bower_components" - def excludesFile = new File("./lib_exclude") - if(excludesFile.exists()) { - exclude(excludesFile.readLines().collect({ bowerDir + it })) - } } // -- code-coverage -jacoco { - toolVersion = '0.8.7' -} - jacocoTestReport { group = 'Reporting' description = 'Generate Jacoco coverage reports after running tests.' @@ -377,19 +340,47 @@ jacocoTestReport { } } -task dockerize(type: Copy) { +tasks.register('dockerize', Copy) { from 'src/main/dist/Dockerfile' into "${buildDir}/dockerize" filter(ReplaceTokens, tokens: [ALFIO_VERSION: project.version]) } -task distribution(type: Copy) { +tasks.register('frontendNpmInstall', NpmTask) { + args = ['--prefix', "${project.projectDir}/frontend", 'install'] +} + +tasks.register('frontendBuild', NpmTask) { + dependsOn frontendNpmInstall + args = ['--prefix', "${project.projectDir}/frontend", 'run', 'build'] + outputs.dir("${project.projectDir}/frontend/dist") +} + +clean.doFirst { + delete "${project.projectDir}/frontend/dist" +} + +tasks.register('publicFrontendIndexTransform', FrontendIndexTransformTask) { + dependsOn frontendBuild + basePath.set("frontend-public/") + indexHtml.set(layout.projectDirectory.file("frontend/dist/alfio-public-frontend/index.html")) + indexHtmlTransformed.set(layout.buildDirectory.file("index-transformed/alfio-public-frontend-index.html")) +} + +tasks.register('adminFrontendIndexTransform', FrontendIndexTransformTask) { + dependsOn frontendBuild + basePath.set("frontend-admin/") + indexHtml.set(layout.projectDirectory.file("frontend/dist/alfio-admin-frontend/index.html")) + indexHtmlTransformed.set(layout.buildDirectory.file("index-transformed/alfio-admin-frontend-index.html")) +} + +tasks.register('distribution', Copy) { from zipTree("${project.buildDir}/libs/alfio-${project.version}-boot.war") into "${buildDir}/dockerize" - dependsOn build, dockerize + dependsOn publicFrontendIndexTransform, build, dockerize } -task clever(type: Copy) { +tasks.register('clever', Copy) { from new File(project.buildDir, "libs/alfio-${project.version}-boot.war") rename(new Transformer() { @Override @@ -398,31 +389,83 @@ task clever(type: Copy) { } }) into "${project.buildDir}/clevercloud" - dependsOn build + dependsOn publicFrontendIndexTransform, adminFrontendIndexTransform, build } release { buildTasks = ['distribution'] git { - requireBranch = '' - pushToRemote = 'origin' - signTag = true + requireBranch.set('') + pushToRemote.set('origin') + signTag.set(true) } } -// see https://github.com/freefair/gradle-plugins/issues/31#issuecomment-475355674 -// since we have a custom lombok.config configuration file, we disable automatic override -generateLombokConfig.enabled = false -// MJML email templates translations to HTML -node { - download = true +bootWar { + dependsOn publicFrontendIndexTransform, adminFrontendIndexTransform + archiveClassifier.set('boot') + from(tasks.named("frontendBuild")) { + into 'resources' + } + from(tasks.named("publicFrontendIndexTransform")) { + rename 'alfio-public-frontend-index.html', 'WEB-INF/classes/alfio-public-frontend-index.html' + } + from(tasks.named("adminFrontendIndexTransform")) { + rename 'alfio-admin-frontend-index.html', 'WEB-INF/classes/alfio-admin-frontend-index.html' + } + def bowerDir = "resources/bower_components" + def excludesFile = new File("./lib_exclude") + if(excludesFile.exists()) { + exclude(excludesFile.readLines().collect({ bowerDir + it })) + } } -task mjmlToHtml( type: NodeTask, dependsOn: 'npmInstall' ) { - script = file( 'src/main/node/mjmlToHtml.js' ) +// MJML email templates translations to HTML + +tasks.register('mjmlToHtml', NodeTask) { + dependsOn npmInstall + script = file('src/main/node/mjmlToHtml.js') } + // We build HTML templates from MJML source files and then save them under "build/generated/resources" in order to be // included in the final artifact. // TODO should we do the same for plaintext templates? See https://gist.github.com/brasilikum/3cd515bad5541ca6c76873faf10445c2 processResources.dependsOn(mjmlToHtml) sourceSets.main.output.dir file("$buildDir/generated/resources"), builtBy: mjmlToHtml + +// transform index.html +abstract class FrontendIndexTransformTask extends org.gradle.api.DefaultTask { + + @org.gradle.api.tasks.InputFile + abstract org.gradle.api.file.RegularFileProperty getIndexHtml() + + @org.gradle.api.tasks.OutputFile + abstract org.gradle.api.file.RegularFileProperty getIndexHtmlTransformed() + + @org.gradle.api.tasks.Input + abstract Property getBasePath() + + FrontendIndexTransformTask() { + basePath.convention("frontend-public/") + } + + + @org.gradle.api.tasks.TaskAction + def doWork() { + final resource = indexHtml.get().asFile.newInputStream() + final indexDoc = new Parser().parse(new InputStreamReader(resource, StandardCharsets.UTF_8)) + + NodeMatcher scriptNodes = Selector.select().element("script").toMatcher() + + indexDoc.getAllNodesMatching(scriptNodes).stream().forEach({ + it.setAttribute("src", basePath.get() + it.getAttribute("src")) + }) + + NodeMatcher cssNodes = Selector.select().element("link").attrValEq("rel", "stylesheet").toMatcher() + indexDoc.getAllNodesMatching(cssNodes).stream().forEach({ + it.setAttribute("href", basePath.get() + it.getAttribute("href")) + }) + + indexHtmlTransformed.get().asFile.write(HtmlSerializer.serialize(indexDoc), "UTF-8", false) + } +} \ No newline at end of file diff --git a/frontend/.editorconfig b/frontend/.editorconfig new file mode 100644 index 0000000000..59d9a3a3e7 --- /dev/null +++ b/frontend/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000000..9f4777da7a --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,43 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.vscode/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000000..b06dd9d306 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,27 @@ +# Frontend + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.1. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/angular.json b/frontend/angular.json new file mode 100644 index 0000000000..b1fad4dcb6 --- /dev/null +++ b/frontend/angular.json @@ -0,0 +1,285 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "common": { + "projectType": "library", + "root": "projects/common", + "sourceRoot": "projects/common/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/common/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/common/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/common/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/common/tsconfig.spec.json", + "polyfills": "projects/common/polyfills.ts" + } + } + } + }, + "public": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "projects/public", + "sourceRoot": "projects/public/src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "aot": true, + "outputPath": "dist/alfio-public-frontend", + "index": "projects/public/src/index.html", + "main": "projects/public/src/main.ts", + "polyfills": "projects/public/src/polyfills.ts", + "tsConfig": "projects/public/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "projects/public/src/favicon.ico", + "projects/public/src/assets" + ], + "styles": [ + "projects/public/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/public/node_modules", + "projects/common/style" + ] + }, + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ], + "outputHashing": "all", + "fileReplacements": [ + { + "replace": "projects/public/src/environments/environment.ts", + "with": "projects/public/src/environments/environment.prod.ts" + } + ], + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": true + } + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "proxyConfig": "projects/public/proxy.config.json" + }, + "configurations": { + "production": { + "browserTarget": "public:build:production" + }, + "development": { + "browserTarget": "public:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "public:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": "projects/public/src/polyfills.ts", + "tsConfig": "projects/public/tsconfig.spec.json", + "inlineStyleLanguage": "scss", + "assets": [ + "projects/public/src/favicon.ico", + "projects/public/src/assets" + ], + "styles": [ + "projects/public/src/styles.scss" + ], + "scripts": [] + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": [ + "src/**/*.ts", + "src/**/*.html" + ] + } + } + } + }, + "admin": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "projects/admin", + "sourceRoot": "projects/admin/src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/alfio-admin-frontend", + "index": "projects/admin/src/index.html", + "main": "projects/admin/src/main.ts", + "polyfills": "projects/admin/src/polyfills.ts", + "tsConfig": "projects/admin/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "projects/admin/src/favicon.ico", + "projects/admin/src/assets" + ], + "styles": [ + "projects/admin/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/admin/node_modules", + "projects/common/style" + ] + }, + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all", + "fileReplacements": [ + { + "replace": "projects/admin/src/environments/environment.ts", + "with": "projects/admin/src/environments/environment.prod.ts" + } + ], + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": true + } + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "proxyConfig": "projects/admin/proxy.config.json" + }, + "configurations": { + "production": { + "browserTarget": "admin:build:production" + }, + "development": { + "browserTarget": "admin:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "admin:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": "projects/admin/polyfills.ts", + "tsConfig": "projects/admin/tsconfig.spec.json", + "inlineStyleLanguage": "scss", + "assets": [ + "projects/admin/src/favicon.ico", + "projects/admin/src/assets" + ], + "styles": [ + "projects/admin/src/styles.scss" + ], + "scripts": [] + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": [ + "src/**/*.ts", + "src/**/*.html" + ] + } + } + } + } + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000000..a0d24bc389 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,21211 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "hasInstallScript": true, + "dependencies": { + "@angular/animations": "^14.2.0", + "@angular/common": "^14.2.0", + "@angular/compiler": "^14.2.0", + "@angular/core": "^14.2.0", + "@angular/forms": "^14.2.0", + "@angular/platform-browser": "^14.2.0", + "@angular/platform-browser-dynamic": "^14.2.0", + "@angular/router": "^14.2.0", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.2.10", + "@angular/cli": "~14.2.10", + "@angular/compiler-cli": "^14.2.0", + "@types/jasmine": "~4.0.0", + "jasmine-core": "~4.3.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.0.0", + "ng-packagr": "^14.2.0", + "typescript": "~4.7.2" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", + "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.10.tgz", + "integrity": "sha512-/6YmPrgataj1jD2Uqd1ED+CG4DaZGacoeZd/89hH7hF76Nno8K18DrSOqJAEmDnOWegpSRGVLd0qP09IHmaG5w==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.10", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/architect/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/@angular-devkit/build-angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.10.tgz", + "integrity": "sha512-VCeZAyq4uPCJukKInaSiD4i/GgxgcU4jFlLFQtoYNmaBS4xbPOymL19forRIihiV0dwNEa2L694vRTAPMBxIfw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/build-webpack": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.10", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.16", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.74.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.15.5" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "@angular/localize": "^14.0.0", + "@angular/service-worker": "^14.0.0", + "karma": "^6.3.0", + "ng-packagr": "^14.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.6.2 <4.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@angular-devkit/build-angular/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs/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/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.10.tgz", + "integrity": "sha512-h+2MaSY7QSvoJ3R+Hvin21jVCfPGOTLdASIUk4Jmq6J3y5BSku3KSSaV8dWoBOBkFCwQyPQMRjiHoHKLpC1K7g==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.10", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/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/@angular-devkit/core": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.10.tgz", + "integrity": "sha512-K4AO7mROTdbhQ7chtyQd6oPwmuL+BPUh+wn6Aq1qrmYJK4UZYFOPp8fi/Ehs8meCEeywtrssOPfrOE4Gsre9dg==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/core/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/@angular-devkit/schematics": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.10.tgz", + "integrity": "sha512-MMp31KpJTwKHisXOq+6VOXYApq97hZxFaFmZk396X5aIFTCELUwjcezQDk+u2nEs5iK/COUfnN3plGcfJxYhQA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.10", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/schematics/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/@angular/animations": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.12.tgz", + "integrity": "sha512-gwdnFZkvVUr+enUNfhfCGRGGqNHn1+vTA81apLfHYhJxgjiLUtETc4KTOrQevtDm022pEd+LSrvr8r+7ag+jkw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.12" + } + }, + "node_modules/@angular/cli": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.10.tgz", + "integrity": "sha512-gX9sAKOwq4lKdPWeABB7TzKDHdjQXvkUU8NmPJA6mEAVXvm3lhQtFvHDalZstwK8au2LY0LaXTcEtcKYOt3AXQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "@schematics/angular": "14.2.10", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.2", + "resolve": "1.22.1", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.12.tgz", + "integrity": "sha512-oZunh9wfInFWhNO1P8uoEs/o4u8kerKMhw8GruywKm1TV7gHDP2Fi5WHGjFqq3XYptgBTPCTSEfyLX6Cwq1PUw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.12.tgz", + "integrity": "sha512-u2MH9+NRwbbFDRNiPWPexed9CnCq9+pGHLuyACSP2uR6Ik68cE6cayeZbIeoEV5vWpda/XsLmJgPJysw7dAZLQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.12" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.12.tgz", + "integrity": "sha512-9Gkb9KFkaQPz8XaS8ZwwTioRZ4ywykdAWyceICEi78/Y9ConYrTX2SbFogzI2dPUZU8a04tMlbqTSmHjVbJftQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/main-ngcc.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.2.12", + "typescript": ">=4.6.2 <4.9" + } + }, + "node_modules/@angular/core": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.12.tgz", + "integrity": "sha512-sGQxU5u4uawwvJa6jOTmGoisJiQ5HIN/RoBw99CmoqZIVyUSg9IRJJC1KVdH8gbpWBNLkElZv21lwJTL/msWyg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4 || ~0.12.0" + } + }, + "node_modules/@angular/forms": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.12.tgz", + "integrity": "sha512-7abYlGIT2JnAtutQUlH3fQS6QEpbfftgvsVcZJCyvX0rXL3u2w2vUQkDHJH4YJJp3AHFVCH4/l7R4VcaPnrwvA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.12.tgz", + "integrity": "sha512-vOarWym8ucl1gjYWCzdwyBha+MTvL381mvTTUu8aUx6nVhHFjv4bvpjlZnZgojecqUPyxOwmPLLHvCZPJVHZYg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/animations": "14.2.12", + "@angular/common": "14.2.12", + "@angular/core": "14.2.12" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.12.tgz", + "integrity": "sha512-oZhNJeaBmgw8+KBSYpKz2RYqEDyETC+HJXH8dwIFcP6BqqwL2NE70FdSR7EnOa5c41MEtTmMCGhrJSFR60x5/w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.12", + "@angular/compiler": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12" + } + }, + "node_modules/@angular/router": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.12.tgz", + "integrity": "sha512-r5tVus5RJDNc4U2v0jMtjPiAS1xDsVsJ70lS313DgZmBDHIVZP1cWIehdxwgNlGwQQtAA36eG7toBwqUU3gb/A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", + "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", + "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "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.18.6", + "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.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@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==", + "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-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.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==", + "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-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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-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==", + "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-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@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-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@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-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "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==", + "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==", + "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.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "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-private-property-in-object": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@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-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==", + "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-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-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-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "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-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-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", + "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.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.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "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-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^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-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^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-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "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-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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.18.6", + "@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-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "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" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", + "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "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/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/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "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/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@ngtools/webpack": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz", + "integrity": "sha512-sLHapZLVub6mEz5b19tf1VfIV1w3tYfg7FNPLeni79aldxu1FbP1v2WmiFAnMzrswqyK0bhTtxrl+Z/CLKqyoQ==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "typescript": ">=4.6.2 <4.9", + "webpack": "^5.54.0" + } + }, + "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/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/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/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script/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/@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.8" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^2.42.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@schematics/angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.10.tgz", + "integrity": "sha512-YFTc/9QJdx422XcApizEcVLKoyknu8b9zHIlAepZCu7WkV8GPT0hvVEHQ7KBWys5aQ7pPZMT0JpZLeAz0F2xYQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "jsonc-parser": "3.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.31", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.32", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", + "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.0.3.tgz", + "integrity": "sha512-Opp1LvvEuZdk8fSSvchK2mZwhVrsNT0JgJE9Di6MjnaIpmEXM8TLCPPrVtNTYh8+5MPdY8j9bAHMu2SSfwpZJg==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.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/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "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/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "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-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "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/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "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-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "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/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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 + }, + "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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "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/caniuse-lite": { + "version": "1.0.30001442", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz", + "integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "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/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js-compat": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz", + "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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/critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/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/critters/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/critters/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/critters/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/critters/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/critters/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/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/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/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "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, + "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-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, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz", + "integrity": "sha512-JYlIsE7eKHSi0UNuCyo96YuIDFqvhGgHw4Ck6lsN+DP0Tp8M64UTDT2trGbkMDqnCoEjks7CkS0XcjU0rkvBdg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + }, + "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/cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", + "dev": true + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "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/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "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/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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, + "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" + } + ] + }, + "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, + "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, + "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/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, + "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/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/engine.io": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.5.tgz", + "integrity": "sha512-mjEyaa4zhuuRhaSLOdjEb57X0XPP9JEsnXI4E+ivhwT0GgzUogARx4MqoY1jQyB+4Bkz3BUOmzL7t9RMKmlG3g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "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-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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/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/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/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/esrecurse/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/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/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "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/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "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.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "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/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "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/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "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==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "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-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/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "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/globby": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "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/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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-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-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "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/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "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/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "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/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", + "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==", + "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/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/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/injection-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.4.0.tgz", + "integrity": "sha512-6jiJt0tCAo9zjHbcwLiPL+IuNe9SQ6a9g0PEzafThW3fOQi0mrmiJGBJvDD6tmhPh8cQHIQtCOrJuBfQME4kPA==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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-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-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-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-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-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "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-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "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/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "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-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/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-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-lib-source-maps/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/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.3.0.tgz", + "integrity": "sha512-qybtBUesniQdW6n+QIHMng2vDOHscIC/dEXjW+JzO9+LoAZMb03RCUC5xFOv/btSKPm1xL42fn+RjlU4oB42Lg==", + "dev": true + }, + "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-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "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/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-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": "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/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/jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/karma": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", + "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", + "dev": true, + "peerDependencies": { + "jasmine-core": "^4.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/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/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/karma/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/karma/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/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/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/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, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "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/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "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==", + "dev": true + }, + "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/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log4js": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.1.tgz", + "integrity": "sha512-lzbd0Eq1HRdWM2abSD7mk6YIVY0AogGJzb/z+lqzRk+8+XJP+M6L1MS5FUSc3jjGru4dbKjEMJmqlsoYYpuivQ==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + }, + "engines": { + "node": ">=8.0" + } + }, + "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/magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", + "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": 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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/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/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/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/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "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/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "dev": true, + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ng-packagr": { + "version": "14.2.2", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-14.2.2.tgz", + "integrity": "sha512-AqwHcMM6x+JkCHT++IsbulnTdyoXcC2Cr4tbPamuieacc77+fFbB195hdcqEFwsKX5410cymx/ZUyHird9rxlg==", + "dev": true, + "dependencies": { + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.1.3", + "ajv": "^8.10.0", + "ansi-colors": "^4.1.1", + "browserslist": "^4.20.0", + "cacache": "^16.0.0", + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "dependency-graph": "^0.11.0", + "esbuild-wasm": "^0.15.0", + "find-cache-dir": "^3.3.2", + "glob": "^8.0.0", + "injection-js": "^2.4.0", + "jsonc-parser": "^3.0.0", + "less": "^4.1.2", + "ora": "^5.1.0", + "postcss": "^8.4.8", + "postcss-preset-env": "^7.4.2", + "postcss-url": "^10.1.3", + "rollup": "^2.70.0", + "rollup-plugin-sourcemaps": "^0.6.3", + "rxjs": "^7.5.5", + "sass": "^1.49.9", + "stylus": "^0.59.0" + }, + "bin": { + "ng-packagr": "cli/main.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "optionalDependencies": { + "esbuild": "^0.15.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0 || ^14.0.0-next || ^14.2.0-next", + "tslib": "^2.3.0", + "typescript": ">=4.6.2 <4.9" + } + }, + "node_modules/ng-packagr/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ng-packagr/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ng-packagr/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/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/node-releases": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", + "dev": true + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-packlist/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-packlist/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist/node_modules/npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dev": true, + "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/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/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/ora/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/ora/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/ora/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/ora/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/ora/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/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.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-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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/pacote": { + "version": "13.6.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pacote/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "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/parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dev": true, + "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-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "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.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "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": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "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.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.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, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.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, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": 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-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "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, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "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, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-url": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", + "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", + "dev": true, + "dependencies": { + "make-dir": "~3.1.0", + "mime": "~2.5.2", + "minimatch": "~3.0.4", + "xxhashjs": "~0.2.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-url/node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-url/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "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.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "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/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.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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-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-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/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/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-sourcemaps": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz", + "integrity": "sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.9", + "source-map-resolve": "^0.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "@types/node": ">=10.0.0", + "rollup": ">=0.31.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "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/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/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.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "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": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/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/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/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/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/semver/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/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "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/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz", + "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.1", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "node_modules/socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "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/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.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/source-map-support/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/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "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.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "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/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.4.tgz", + "integrity": "sha512-Ha1Ccw2/N5C/IF8Do6zgNe8F3jQo8MPBnMBGvX0QjNv/I97BcNRzK6/mzOpZHHK7DjMLTI3c7Xw7Y1KvdChkvw==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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/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-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/stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://opencollective.com/stylus" + } + }, + "node_modules/stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "stylus": ">=0.52.4", + "webpack": "^5.0.0" + } + }, + "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-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/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/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/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "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/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "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/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "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/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "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/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "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/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/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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/validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/webpack/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/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/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/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "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/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "dependencies": { + "cuint": "^0.2.2" + } + }, + "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": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "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.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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, + "engines": { + "node": ">=12" + } + }, + "node_modules/zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "dependencies": { + "tslib": "^2.3.0" + } + } + }, + "dependencies": { + "@adobe/css-tools": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", + "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/architect": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.10.tgz", + "integrity": "sha512-/6YmPrgataj1jD2Uqd1ED+CG4DaZGacoeZd/89hH7hF76Nno8K18DrSOqJAEmDnOWegpSRGVLd0qP09IHmaG5w==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.10", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/build-angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.10.tgz", + "integrity": "sha512-VCeZAyq4uPCJukKInaSiD4i/GgxgcU4jFlLFQtoYNmaBS4xbPOymL19forRIihiV0dwNEa2L694vRTAPMBxIfw==", + "dev": true, + "requires": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/build-webpack": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.10", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild": "0.15.5", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.16", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.74.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.10.tgz", + "integrity": "sha512-h+2MaSY7QSvoJ3R+Hvin21jVCfPGOTLdASIUk4Jmq6J3y5BSku3KSSaV8dWoBOBkFCwQyPQMRjiHoHKLpC1K7g==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1402.10", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.10.tgz", + "integrity": "sha512-K4AO7mROTdbhQ7chtyQd6oPwmuL+BPUh+wn6Aq1qrmYJK4UZYFOPp8fi/Ehs8meCEeywtrssOPfrOE4Gsre9dg==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.10.tgz", + "integrity": "sha512-MMp31KpJTwKHisXOq+6VOXYApq97hZxFaFmZk396X5aIFTCELUwjcezQDk+u2nEs5iK/COUfnN3plGcfJxYhQA==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.10", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular/animations": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.12.tgz", + "integrity": "sha512-gwdnFZkvVUr+enUNfhfCGRGGqNHn1+vTA81apLfHYhJxgjiLUtETc4KTOrQevtDm022pEd+LSrvr8r+7ag+jkw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/cli": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.10.tgz", + "integrity": "sha512-gX9sAKOwq4lKdPWeABB7TzKDHdjQXvkUU8NmPJA6mEAVXvm3lhQtFvHDalZstwK8au2LY0LaXTcEtcKYOt3AXQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "@schematics/angular": "14.2.10", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.2", + "resolve": "1.22.1", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + } + }, + "@angular/common": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.12.tgz", + "integrity": "sha512-oZunh9wfInFWhNO1P8uoEs/o4u8kerKMhw8GruywKm1TV7gHDP2Fi5WHGjFqq3XYptgBTPCTSEfyLX6Cwq1PUw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.12.tgz", + "integrity": "sha512-u2MH9+NRwbbFDRNiPWPexed9CnCq9+pGHLuyACSP2uR6Ik68cE6cayeZbIeoEV5vWpda/XsLmJgPJysw7dAZLQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler-cli": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.12.tgz", + "integrity": "sha512-9Gkb9KFkaQPz8XaS8ZwwTioRZ4ywykdAWyceICEi78/Y9ConYrTX2SbFogzI2dPUZU8a04tMlbqTSmHjVbJftQ==", + "dev": true, + "requires": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + } + }, + "@angular/core": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.12.tgz", + "integrity": "sha512-sGQxU5u4uawwvJa6jOTmGoisJiQ5HIN/RoBw99CmoqZIVyUSg9IRJJC1KVdH8gbpWBNLkElZv21lwJTL/msWyg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/forms": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.12.tgz", + "integrity": "sha512-7abYlGIT2JnAtutQUlH3fQS6QEpbfftgvsVcZJCyvX0rXL3u2w2vUQkDHJH4YJJp3AHFVCH4/l7R4VcaPnrwvA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.12.tgz", + "integrity": "sha512-vOarWym8ucl1gjYWCzdwyBha+MTvL381mvTTUu8aUx6nVhHFjv4bvpjlZnZgojecqUPyxOwmPLLHvCZPJVHZYg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.12.tgz", + "integrity": "sha512-oZhNJeaBmgw8+KBSYpKz2RYqEDyETC+HJXH8dwIFcP6BqqwL2NE70FdSR7EnOa5c41MEtTmMCGhrJSFR60x5/w==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/router": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.12.tgz", + "integrity": "sha512-r5tVus5RJDNc4U2v0jMtjPiAS1xDsVsJ70lS313DgZmBDHIVZP1cWIehdxwgNlGwQQtAA36eG7toBwqUU3gb/A==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", + "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", + "dev": true + }, + "@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + } + }, + "@babel/helpers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", + "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", + "dev": true, + "requires": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "dev": true + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "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.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@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" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", + "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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.18.6", + "@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-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@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" + } + }, + "@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", + "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, + "@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "requires": {} + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "dev": true, + "optional": true + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@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, + "requires": { + "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" + } + }, + "@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 + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@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 + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@ngtools/webpack": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz", + "integrity": "sha512-sLHapZLVub6mEz5b19tf1VfIV1w3tYfg7FNPLeni79aldxu1FbP1v2WmiFAnMzrswqyK0bhTtxrl+Z/CLKqyoQ==", + "dev": true, + "requires": {} + }, + "@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, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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 + }, + "@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, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, + "@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@schematics/angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.10.tgz", + "integrity": "sha512-YFTc/9QJdx422XcApizEcVLKoyknu8b9zHIlAepZCu7WkV8GPT0hvVEHQ7KBWys5aQ7pPZMT0JpZLeAz0F2xYQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "jsonc-parser": "3.1.0" + } + }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/express": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.31", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.32", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", + "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.0.3.tgz", + "integrity": "sha512-Opp1LvvEuZdk8fSSvchK2mZwhVrsNT0JgJE9Di6MjnaIpmEXM8TLCPPrVtNTYh8+5MPdY8j9bAHMu2SSfwpZJg==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/node": { + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "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, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "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 + }, + "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, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "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, + "requires": { + "@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" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "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 + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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 + }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001442", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz", + "integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==", + "dev": true + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "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, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "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 + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "core-js-compat": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz", + "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@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" + } + }, + "critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + } + }, + "css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "requires": {} + }, + "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, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "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 + }, + "cssdb": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz", + "integrity": "sha512-JYlIsE7eKHSi0UNuCyo96YuIDFqvhGgHw4Ck6lsN+DP0Tp8M64UTDT2trGbkMDqnCoEjks7CkS0XcjU0rkvBdg==", + "dev": true + }, + "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 + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "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 + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "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, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, + "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 + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "engine.io": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", + "dev": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + } + }, + "engine.io-parser": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.5.tgz", + "integrity": "sha512-mjEyaa4zhuuRhaSLOdjEb57X0XPP9JEsnXI4E+ivhwT0GgzUogARx4MqoY1jQyB+4Bkz3BUOmzL7t9RMKmlG3g==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, + "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, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "optional": true, + "requires": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "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 + }, + "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, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "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 + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@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" + } + }, + "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 + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "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, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "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 + }, + "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 + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "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 + }, + "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 + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "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, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "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 + }, + "globby": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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 + }, + "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 + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "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 + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "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, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "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 + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "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, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true + }, + "immutable": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", + "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==", + "dev": true + }, + "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, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "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 + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true + }, + "injection-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.4.0.tgz", + "integrity": "sha512-6jiJt0tCAo9zjHbcwLiPL+IuNe9SQ6a9g0PEzafThW3fOQi0mrmiJGBJvDD6tmhPh8cQHIQtCOrJuBfQME4kPA==", + "dev": true, + "requires": { + "tslib": "^2.0.0" + } + }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "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 + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "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 + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "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, + "requires": { + "@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" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "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 + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jasmine-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.3.0.tgz", + "integrity": "sha512-qybtBUesniQdW6n+QIHMng2vDOHscIC/dEXjW+JzO9+LoAZMb03RCUC5xFOv/btSKPm1xL42fn+RjlU4oB42Lg==", + "dev": true + }, + "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, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "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, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "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 + }, + "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 + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "karma": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "dependencies": { + "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 + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "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" + } + }, + "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 + } + } + }, + "karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "requires": { + "which": "^1.2.1" + } + }, + "karma-coverage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "requires": { + "jasmine-core": "^4.1.0" + } + }, + "karma-jasmine-html-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", + "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", + "dev": true, + "requires": {} + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "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 + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true + }, + "less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "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, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true + }, + "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, + "optional": true + } + } + }, + "less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "requires": { + "klona": "^2.0.4" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "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 + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true + }, + "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, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "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 + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.1.tgz", + "integrity": "sha512-lzbd0Eq1HRdWM2abSD7mk6YIVY0AogGJzb/z+lqzRk+8+XJP+M6L1MS5FUSc3jjGru4dbKjEMJmqlsoYYpuivQ==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + } + }, + "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, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", + "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "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 + }, + "mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "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 + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "ng-packagr": { + "version": "14.2.2", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-14.2.2.tgz", + "integrity": "sha512-AqwHcMM6x+JkCHT++IsbulnTdyoXcC2Cr4tbPamuieacc77+fFbB195hdcqEFwsKX5410cymx/ZUyHird9rxlg==", + "dev": true, + "requires": { + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.1.3", + "ajv": "^8.10.0", + "ansi-colors": "^4.1.1", + "browserslist": "^4.20.0", + "cacache": "^16.0.0", + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "dependency-graph": "^0.11.0", + "esbuild": "^0.15.0", + "esbuild-wasm": "^0.15.0", + "find-cache-dir": "^3.3.2", + "glob": "^8.0.0", + "injection-js": "^2.4.0", + "jsonc-parser": "^3.0.0", + "less": "^4.1.2", + "ora": "^5.1.0", + "postcss": "^8.4.8", + "postcss-preset-env": "^7.4.2", + "postcss-url": "^10.1.3", + "rollup": "^2.70.0", + "rollup-plugin-sourcemaps": "^0.6.3", + "rxjs": "^7.5.5", + "sass": "^1.49.9", + "stylus": "^0.59.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-gyp": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", + "dev": true + }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "requires": { + "abbrev": "^1.0.0" + } + }, + "normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "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 + }, + "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 + }, + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^2.0.0" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true + } + } + }, + "npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + } + }, + "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, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "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, + "requires": { + "boolbase": "^1.0.0" + } + }, + "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==", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "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, + "requires": { + "p-try": "^2.0.0" + } + }, + "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, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + } + } + }, + "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 + }, + "pacote": { + "version": "13.6.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "dev": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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, + "requires": { + "callsites": "^3.0.0" + } + }, + "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, + "requires": { + "@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" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "requires": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "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 + }, + "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==", + "dev": true + }, + "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 + }, + "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 + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "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 + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "requires": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" + } + }, + "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, + "requires": { + "find-up": "^4.0.0" + } + }, + "postcss": { + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "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, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "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, + "requires": {} + }, + "postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "requires": {} + }, + "postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "requires": {} + }, + "postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + } + }, + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "requires": {} + }, + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "requires": {} + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "dev": true, + "requires": {} + }, + "postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "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, + "requires": {} + }, + "postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "requires": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "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, + "requires": {} + }, + "postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-url": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", + "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", + "dev": true, + "requires": { + "make-dir": "~3.1.0", + "mime": "~2.5.2", + "minimatch": "~3.0.4", + "xxhashjs": "~0.2.2" + }, + "dependencies": { + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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 + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "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 + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "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, + "requires": { + "pify": "^2.3.0" + } + }, + "read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true + } + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "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 + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "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 + }, + "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 + }, + "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 + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "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 + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "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 + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-sourcemaps": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz", + "integrity": "sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.9", + "source-map-resolve": "^0.6.0" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "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, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass": { + "version": "1.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "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, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "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 + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socket.io": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz", + "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.1", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.1" + } + }, + "socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "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 + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "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, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + }, + "streamroller": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.4.tgz", + "integrity": "sha512-Ha1Ccw2/N5C/IF8Do6zgNe8F3jQo8MPBnMBGvX0QjNv/I97BcNRzK6/mzOpZHHK7DjMLTI3c7Xw7Y1KvdChkvw==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "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, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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 + }, + "stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + } + }, + "stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + } + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + }, + "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 + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "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, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "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 + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "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 + }, + "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, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "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 + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "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 + }, + "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 + }, + "unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "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 + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "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, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "requires": { + "typed-assert": "^1.0.8" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "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, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "requires": {} + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "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.0.0" + } + }, + "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 + }, + "zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "requires": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000000..309ce19956 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,41 @@ +{ + "name": "frontend", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build common && ng build public && ng build admin", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "postinstall": "(cd projects/common && npm install) && (cd projects/public && npm install) && (cd projects/admin && npm install)", + "prebuild": "npm --prefix projects/admin run svg" + }, + "private": true, + "dependencies": { + "@angular/animations": "^14.2.0", + "@angular/common": "^14.2.0", + "@angular/compiler": "^14.2.0", + "@angular/core": "^14.2.0", + "@angular/forms": "^14.2.0", + "@angular/platform-browser": "^14.2.0", + "@angular/platform-browser-dynamic": "^14.2.0", + "@angular/router": "^14.2.0", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.2.10", + "@angular/cli": "~14.2.10", + "@angular/compiler-cli": "^14.2.0", + "@types/jasmine": "~4.0.0", + "jasmine-core": "~4.3.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.0.0", + "ng-packagr": "^14.2.0", + "typescript": "~4.7.2" + } +} diff --git a/frontend/projects/admin/README.md b/frontend/projects/admin/README.md new file mode 100644 index 0000000000..a32b4efa1b --- /dev/null +++ b/frontend/projects/admin/README.md @@ -0,0 +1,38 @@ +# AlfioAdmin + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.10. + +## Icons + +1. Fetch svg icon here: https://fonts.google.com/icons?icon.style=Outlined +2. Put them in `src/assets/svg` +3. Run `npm run svg` to generate icon code +4. Import them in `shared/icons.ts` +5. Reference them with `` + +Note you may need to import the icon component + the list of icons if you are in a new module, see `app.module.ts` or +`dashboard.module.ts`. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/projects/admin/package-lock.json b/frontend/projects/admin/package-lock.json new file mode 100644 index 0000000000..fcf1ac95ff --- /dev/null +++ b/frontend/projects/admin/package-lock.json @@ -0,0 +1,26969 @@ +{ + "name": "alfio-admin", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "alfio-admin", + "version": "0.0.0", + "dependencies": { + "@angular/animations": "^14.2.0", + "@angular/cdk": "^14.2.7", + "@angular/common": "^14.2.0", + "@angular/compiler": "^14.2.0", + "@angular/core": "^14.2.0", + "@angular/forms": "^14.2.0", + "@angular/platform-browser": "^14.2.0", + "@angular/platform-browser-dynamic": "^14.2.0", + "@angular/pwa": "^0.5.3", + "@angular/router": "^14.2.0", + "@ng-bootstrap/ng-bootstrap": "^13.1.1", + "@ngneat/svg-icon": "^6.1.0", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "@popperjs/core": "^2.10.2", + "bootstrap": "^5.2.0", + "ng2-charts": "^4.1.1", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.2.10", + "@angular-eslint/builder": "14.4.0", + "@angular-eslint/eslint-plugin": "14.4.0", + "@angular-eslint/eslint-plugin-template": "14.4.0", + "@angular-eslint/schematics": "14.4.0", + "@angular-eslint/template-parser": "14.4.0", + "@angular/cli": "~14.2.10", + "@angular/compiler-cli": "^14.2.0", + "@angular/localize": "^14.2.0", + "@ngneat/svg-generator": "^6.0.0", + "@types/jasmine": "~4.0.0", + "@typescript-eslint/eslint-plugin": "5.43.0", + "@typescript-eslint/parser": "5.43.0", + "eslint": "^8.28.0", + "jasmine-core": "~4.3.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.0.0", + "typescript": "~4.7.2" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", + "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.10.tgz", + "integrity": "sha512-/6YmPrgataj1jD2Uqd1ED+CG4DaZGacoeZd/89hH7hF76Nno8K18DrSOqJAEmDnOWegpSRGVLd0qP09IHmaG5w==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.10", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/architect/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/@angular-devkit/build-angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.10.tgz", + "integrity": "sha512-VCeZAyq4uPCJukKInaSiD4i/GgxgcU4jFlLFQtoYNmaBS4xbPOymL19forRIihiV0dwNEa2L694vRTAPMBxIfw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/build-webpack": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.10", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.16", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.74.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.15.5" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "@angular/localize": "^14.0.0", + "@angular/service-worker": "^14.0.0", + "karma": "^6.3.0", + "ng-packagr": "^14.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.6.2 <4.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs/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/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.10.tgz", + "integrity": "sha512-h+2MaSY7QSvoJ3R+Hvin21jVCfPGOTLdASIUk4Jmq6J3y5BSku3KSSaV8dWoBOBkFCwQyPQMRjiHoHKLpC1K7g==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.10", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/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/@angular-devkit/core": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.10.tgz", + "integrity": "sha512-K4AO7mROTdbhQ7chtyQd6oPwmuL+BPUh+wn6Aq1qrmYJK4UZYFOPp8fi/Ehs8meCEeywtrssOPfrOE4Gsre9dg==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/core/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/@angular-devkit/schematics": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.10.tgz", + "integrity": "sha512-MMp31KpJTwKHisXOq+6VOXYApq97hZxFaFmZk396X5aIFTCELUwjcezQDk+u2nEs5iK/COUfnN3plGcfJxYhQA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.10", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/schematics/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/@angular-eslint/builder": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.4.0.tgz", + "integrity": "sha512-AhAUFvSg0urtb6Lsowvuxwu6DMXUy0BPwrnfNOBGjRt9vG7F9kgXXAsm5DnIS0GNy/mLZ9mSfa86fv++1e0KUA==", + "dev": true, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.4.0.tgz", + "integrity": "sha512-KMHPHd24s0HVvAP/DxSSqhYBWhwW8FgS/r0Uwv8eWpsIdc/z/Chd2ush2SgPchmmquAXTgOZsbEY7ZmW+XkJfQ==", + "dev": true + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.4.0.tgz", + "integrity": "sha512-2rZQ4mt7tEUW+lI5jjuj3HWaT4VQtWTG6+LDnmuUmx76m8hqQ7NvFUpOcNDofu5KbEVBP+oF2DA6wjoZOIuSOA==", + "dev": true, + "dependencies": { + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/utils": "5.43.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.4.0.tgz", + "integrity": "sha512-d3GM/EU2iWzr+BrITwO4gBf9WfDfuOdTjfinV/zN84oXMFaK2ENo+IP6OEsD9hh36rdPps+m2gFGDdx+rTzBpg==", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/type-utils": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "aria-query": "5.1.3", + "axobject-query": "3.1.1" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/schematics": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.4.0.tgz", + "integrity": "sha512-BrGkPug+CZQWOfmNRsJDrEtYJcxvzF/kLlV7RjvIN9Ky5TjUiJVCeafl3VY6COSY32tjlh2GvBdl1AQKWWovbA==", + "dev": true, + "dependencies": { + "@angular-eslint/eslint-plugin": "14.4.0", + "@angular-eslint/eslint-plugin-template": "14.4.0", + "ignore": "5.2.0", + "strip-json-comments": "3.1.1", + "tmp": "0.2.1" + }, + "peerDependencies": { + "@angular/cli": ">= 14.0.0 < 15.0.0" + } + }, + "node_modules/@angular-eslint/schematics/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.4.0.tgz", + "integrity": "sha512-zq888KpQB0YTEK26mkKcT4fs8LDWWT1oAEXU8DrXhvkikS8XavTSHOWJye/bVZR4oJRFCF5YTJV75DEMcGNIpQ==", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "eslint-scope": "^7.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@angular-eslint/template-parser/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/@angular-eslint/utils": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.4.0.tgz", + "integrity": "sha512-dPHklAVfh+JfueDfXre9Xooq7p5bFyKO2Z6y1agYeofAgHCPIJOPx2AhtFPrOtsc4VXFFiyE9XbowlXh4ogoKQ==", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@typescript-eslint/utils": "5.43.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.11.tgz", + "integrity": "sha512-HOw8xecbKfs7A5Ezjf+BfXKvvwU7X8I0US5Ey6bOuLvpA3QVOGSLw9BeutY5Q2mPWiRgnNNQW+FOd8Pe9gEkpQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.11" + } + }, + "node_modules/@angular/cdk": { + "version": "14.2.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.7.tgz", + "integrity": "sha512-/tEsYaUbDSnfEmKVvAMramIptmhI67O+9STjOV0i+74XR2NospeK0fkbywIANu1n3w6AHGMotvRWJrjmbCElFg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^5.0.0" + }, + "peerDependencies": { + "@angular/common": "^14.0.0 || ^15.0.0", + "@angular/core": "^14.0.0 || ^15.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cdk/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "node_modules/@angular/cli": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.10.tgz", + "integrity": "sha512-gX9sAKOwq4lKdPWeABB7TzKDHdjQXvkUU8NmPJA6mEAVXvm3lhQtFvHDalZstwK8au2LY0LaXTcEtcKYOt3AXQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "@schematics/angular": "14.2.10", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.2", + "resolve": "1.22.1", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.11.tgz", + "integrity": "sha512-a5w7lz4SoUzCwSDnuUPnfbEYPA8ufFiXz44mOv48P4uIb78q3rZ/R/EyWD1O3yJPof0o8aPNKpKZzuRDv3Q8ow==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.11", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.11.tgz", + "integrity": "sha512-QD4tq37qqPxxNK4o0Pd7dJm06evwEPChV67S/ecX3S6UkSDp8lVoWKiVx9htp/5s4iydKZU4eGu9oTOMOLVdOw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.11" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.11.tgz", + "integrity": "sha512-ipIEgueW8bhxVSq6qlgndBLVRCJoTvk1he/TI3w34m2EnZY1ctgGGCm1VbB3XARh+irVesPVMIAxRtjYds7XOw==", + "dependencies": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/main-ngcc.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.2.11", + "typescript": ">=4.6.2 <4.9" + } + }, + "node_modules/@angular/core": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.11.tgz", + "integrity": "sha512-4uEIA6ESMLt2f/ivKuVBpME0IbuFHWmpweN4dwJt83DfJBiBfpqdrFYZHz/Kbkh9cGCiP7L4/eKPRWTlAHehhw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4 || ~0.12.0" + } + }, + "node_modules/@angular/forms": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.11.tgz", + "integrity": "sha512-sItoA3/I8j/pf3zhv8sR37M5dAYUJpezv8rw2fTT2Y+nZJFUpkFWqX2N4qpMlPY0MP9OX++8K8/d2j0Lfi3wJQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.11", + "@angular/core": "14.2.11", + "@angular/platform-browser": "14.2.11", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/localize": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.2.11.tgz", + "integrity": "sha512-vrYv2f6BR1dKebZB+c0O4Arx7iGF1MqN4gHB+V5KHS7UPIc3YnoQn9LaFDRWWazjrXCvq1uf1Cb8qzzu19+lZQ==", + "dependencies": { + "@babel/core": "7.18.9", + "glob": "8.0.3", + "yargs": "^17.2.1" + }, + "bin": { + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.2.11", + "@angular/compiler-cli": "14.2.11" + } + }, + "node_modules/@angular/localize/node_modules/@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/localize/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/platform-browser": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.11.tgz", + "integrity": "sha512-lGi9pF0Kf/GGrVKcfxxfStM2eMSluDTmbcYuVAX28iBn5XEdfsonrkfy2cnxUMnQ7nioMAZBNGOJHbQPKz4jwg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/animations": "14.2.11", + "@angular/common": "14.2.11", + "@angular/core": "14.2.11" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.11.tgz", + "integrity": "sha512-kjcZda+gcAiYd0I3mjLSr6xR/HkUCnmIMyqaFGoHnIDXI2c6wLDxi49pivrJFvUYJPfYAJ6GjlYTM6L9B3XSEQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.11", + "@angular/compiler": "14.2.11", + "@angular/core": "14.2.11", + "@angular/platform-browser": "14.2.11" + } + }, + "node_modules/@angular/pwa": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-0.5.3.tgz", + "integrity": "sha512-htgdGgWHaAHRdGZ1qxkn/4bQZjx2np+A/oGtuN86z+/jWuY4S+lYfPjLQTmq5kZaZDQm+qm0TVvayCQFEAnagg==", + "dependencies": { + "@angular-devkit/core": "0.5.3", + "@angular-devkit/schematics": "0.5.3", + "@schematics/angular": "0.5.3", + "typescript": "~2.6.2" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@angular/pwa/node_modules/@angular-devkit/core": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.5.3.tgz", + "integrity": "sha512-dv4zIZ7Xc/vkio5FGHOxfSva/G9fU/w0uhF3vws3H5yjRVRgdmbQ22dTcLjVMPZBM359xy2KFK+4lFMGuEdLCw==", + "dependencies": { + "ajv": "~5.5.1", + "chokidar": "^1.7.0", + "rxjs": "^6.0.0-beta.3", + "source-map": "^0.5.6" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@angular/pwa/node_modules/@angular-devkit/schematics": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.5.3.tgz", + "integrity": "sha512-sAXaxeizGyadRb1jTtsyBwAMVLcGsGrmQiUw2aEf56uxnEWNNIntY5xPxP3ya0XrgUgG6YdrSNMpHay6qPGtww==", + "dependencies": { + "@angular-devkit/core": "0.5.3", + "@ngtools/json-schema": "^1.1.0", + "rxjs": "^6.0.0-beta.3" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@angular/pwa/node_modules/@schematics/angular": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.5.3.tgz", + "integrity": "sha512-RQ4DMA5lyJ5XtBLpFxFs0UkyStl1j4n0YAojm/MAGI3B7uKB8qTN0txYvCYrbBUPdGhZC8ic9qzUw9UAJfLfUA==", + "dependencies": { + "@angular-devkit/core": "0.5.3", + "@angular-devkit/schematics": "0.5.3", + "typescript": "~2.6.2" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@angular/pwa/node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "node_modules/@angular/pwa/node_modules/anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dependencies": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "node_modules/@angular/pwa/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==", + "dependencies": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha512-mk8fAWcRUOxY7btlLtitj3A45jOwSAxH4tOFOoEGbVsl6cL6pPMWUy7dwZ/canfj3QEdP6FHSnf/l1c6/WkzVg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dependencies": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + }, + "optionalDependencies": { + "fsevents": "^1.0.0" + } + }, + "node_modules/@angular/pwa/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@angular/pwa/node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==" + }, + "node_modules/@angular/pwa/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/@angular/pwa/node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/@angular/pwa/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==" + }, + "node_modules/@angular/pwa/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", + "dependencies": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/@angular/pwa/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/readdirp/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular/pwa/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/@angular/pwa/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/@angular/pwa/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/pwa/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@angular/pwa/node_modules/typescript": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha512-L0QfAFYU8U/ucTqDptb0Hq67++OwqdSKDAAXmpaECxEkPOIpydxh4p0p9BRDG0kliZHFJBAWZDHR0nomxF/E7A==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@angular/router": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.11.tgz", + "integrity": "sha512-AbnyKXabar2WsG3fL24O1xdwkcRhRKI7u2vc9D8bcp2ks5GOJNxfbtG2Z6PSO18vtDszQxwELRe2cOEe+0TmPQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.11", + "@angular/core": "14.2.11", + "@angular/platform-browser": "14.2.11", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "dependencies": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz", + "integrity": "sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.19.1", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "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.18.6", + "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.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@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==", + "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-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.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==", + "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-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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-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==", + "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-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@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-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz", + "integrity": "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.1" + }, + "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==", + "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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "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-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@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-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==", + "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-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-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-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "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-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-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz", + "integrity": "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz", + "integrity": "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.19.1", + "@babel/helper-split-export-declaration": "^7.18.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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz", + "integrity": "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "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-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^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-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^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-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz", + "integrity": "sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "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-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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.18.6", + "@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-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "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" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", + "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "dependencies": { + "@babel/types": "^7.20.2", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@babel/types": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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 + }, + "node_modules/@eslint/eslintrc/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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/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/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "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==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "peer": true + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@ng-bootstrap/ng-bootstrap": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-13.1.1.tgz", + "integrity": "sha512-R6qnmFKT2EwwijBHw7rUXqyo5W90OImHOv7BlsxMNnZLIksWIhqwU00k4UBTfRTnd6JsTPuj/co3MaP61ajILA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^14.1.0", + "@angular/core": "^14.1.0", + "@angular/forms": "^14.1.0", + "@angular/localize": "^14.1.0", + "@popperjs/core": "^2.10.2", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ngneat/svg-generator": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ngneat/svg-generator/-/svg-generator-6.0.0.tgz", + "integrity": "sha512-jHvkTlLyeNHcedVALyI0PiaLXt4CkLEW11FAsahXZTB8+v3McXquqqNAdHg1Gxyp1H1xvPDFf9j+KZ5xOIFJvw==", + "dev": true, + "dependencies": { + "camelcase": "6.2.0", + "chokidar": "3.5.3", + "commander": "9.4.1", + "cosmiconfig": "7.0.1", + "fs-extra": "10.1.0", + "glob": "8.0.3", + "lodash.kebabcase": "4.1.1", + "svgo": "2.8.0", + "typescript": "4.8.4" + }, + "bin": { + "svg-generator": "index.js" + } + }, + "node_modules/@ngneat/svg-generator/node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ngneat/svg-generator/node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/@ngneat/svg-generator/node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "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/@ngneat/svg-generator/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ngneat/svg-generator/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, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@ngneat/svg-generator/node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@ngneat/svg-generator/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@ngneat/svg-icon": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@ngneat/svg-icon/-/svg-icon-6.1.0.tgz", + "integrity": "sha512-9a3FuvhSBlJMBEk0HdESWWM5zReYE0VESjnwbNjLvEN64IaIjGk+mJlPzqX3y0WgBW8cx9+1/bnpAz/o+mHQhQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">= 14.0.0" + } + }, + "node_modules/@ngtools/json-schema": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz", + "integrity": "sha512-6i322P+RDn7nFiqdKqGGfvjyhEN551o8NsKxE0/lBAXzu0kUA8wlWa8d/RU1+VJtQ0+GOKFc7xHmoKuw7gt+Lw==", + "engines": { + "node": ">= 4.1.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/@ngtools/webpack": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz", + "integrity": "sha512-sLHapZLVub6mEz5b19tf1VfIV1w3tYfg7FNPLeni79aldxu1FbP1v2WmiFAnMzrswqyK0bhTtxrl+Z/CLKqyoQ==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "typescript": ">=4.6.2 <4.9", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=13.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ngx-translate/http-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-7.0.0.tgz", + "integrity": "sha512-j+NpXXlcGVdyUNyY/qsJrqqeAdJdizCd+GKh3usXExSqy1aE9866jlAIL+xrfDU4w+LiMoma5pgE4emvFebZmA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@ngx-translate/core": ">=14.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "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/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/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/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script/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/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@schematics/angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.10.tgz", + "integrity": "sha512-YFTc/9QJdx422XcApizEcVLKoyknu8b9zHIlAepZCu7WkV8GPT0hvVEHQ7KBWys5aQ7pPZMT0JpZLeAz0F2xYQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "jsonc-parser": "3.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.0.3.tgz", + "integrity": "sha512-Opp1LvvEuZdk8fSSvchK2mZwhVrsNT0JgJE9Di6MjnaIpmEXM8TLCPPrVtNTYh8+5MPdY8j9bAHMu2SSfwpZJg==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz", + "integrity": "sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/type-utils": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "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" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.43.0.tgz", + "integrity": "sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/typescript-estree": "5.43.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.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz", + "integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.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/type-utils": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz", + "integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz", + "integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==", + "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.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz", + "integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.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/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/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz", + "integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/typescript-estree": "5.43.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "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" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz", + "integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.43.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/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "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/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.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/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "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/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "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-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "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==", + "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==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/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/arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==", + "dependencies": { + "arr-flatten": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "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-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "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-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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 + }, + "node_modules/bootstrap": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.2.tgz", + "integrity": "sha512-dEtzMTV71n6Fhmbg4fYJzQsw1N29hJKO1js5ackCgIpDcGid2ETMGC6zwSYw09v05Y+oRdQ9loC54zB1La3hHQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.6" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "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/caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "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==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chart.js": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz", + "integrity": "sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==", + "peer": true, + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=7" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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==" + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js-compat": { + "version": "3.26.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.1.tgz", + "integrity": "sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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/critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/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/critters/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/critters/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/critters/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/critters/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/critters/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/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/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/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "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, + "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, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/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/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, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.1.0.tgz", + "integrity": "sha512-Sd99PrFgx28ez4GHu8yoQIufc/70h9oYowDf4EjeIKi8mac9whxRjhM3IaMr6EllP6KKKWtJrMfN6C7T9tIWvQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + }, + "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/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/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/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/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "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/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "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-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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, + "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" + } + ] + }, + "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, + "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, + "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/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "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==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "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-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/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/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/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-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/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/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": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/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/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/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/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/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/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/esrecurse/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/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/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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "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/expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", + "dependencies": { + "is-posix-bracket": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "dependencies": { + "fill-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dependencies": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "engines": { + "node": ">=0.10.0" + } + }, + "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.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "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==" + }, + "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/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "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.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "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/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "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.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "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/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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==", + "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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "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-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-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", + "dependencies": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-base/node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/glob-base/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-base/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "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/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.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "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.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "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/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "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/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "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/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "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/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/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.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-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-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==", + "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-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "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.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==", + "dependencies": { + "is-primitive": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "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-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "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-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "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-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.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-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/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "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/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "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-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/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-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-lib-source-maps/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/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.3.0.tgz", + "integrity": "sha512-qybtBUesniQdW6n+QIHMng2vDOHscIC/dEXjW+JzO9+LoAZMb03RCUC5xFOv/btSKPm1xL42fn+RjlU4oB42Lg==", + "dev": true + }, + "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-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "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": "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/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "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": "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/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.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/karma": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-coverage/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma-coverage/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", + "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", + "dev": true, + "peerDependencies": { + "jasmine-core": "^4.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/karma/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/karma/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/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/karma/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/karma/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/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/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, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "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/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "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==", + "dev": true + }, + "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.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": 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/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log4js": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, + "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 + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.11.tgz", + "integrity": "sha512-GvsCITGAyDCxxsJ+X6prJexFQEhOCJaIlUbsAvjzSI5o5O7j2dle3jWvz5Z5aOdpOxW6ol3vI1+0ut+641F1+w==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": 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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "dev": true, + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ng2-charts": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz", + "integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==", + "dependencies": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": ">=14.0.0", + "@angular/common": ">=14.0.0", + "@angular/core": ">=14.0.0", + "chart.js": "^3.4.0 || ^4.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.0.tgz", + "integrity": "sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/node-gyp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-gyp/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/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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==", + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "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-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==", + "dependencies": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/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/ora/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/ora/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/ora/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/ora/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/ora/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/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.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-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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/pacote": { + "version": "13.6.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", + "dependencies": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-glob/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-glob/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "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/parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "engines": { + "node": ">=0.10.0" + } + }, + "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-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "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.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "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/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.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, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.10", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.10.tgz", + "integrity": "sha512-U3BHdgrYhCrwTVcByFHs9EOBoqcKq4Lf3kXwbTi4hhq0qWhl/pDWq2THbv/ICX/Fl9KqeHBb8OVrTf2OaYF07A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.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, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": 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-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", + "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "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, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "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, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "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/preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dependencies": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/randomatic/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "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.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dependencies": { + "is-equal-shallow": "^0.1.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "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.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "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-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, + "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==", + "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.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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-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-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated" + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/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/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "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/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dependencies": { + "ret": "~0.1.10" + } + }, + "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.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "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": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/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/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/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/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "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/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/snapdragon/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/socket.io": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "node_modules/socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "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/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.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/source-map-support/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-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated" + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "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.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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 + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "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-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/stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://opencollective.com/stylus" + } + }, + "node_modules/stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "stylus": ">=0.52.4", + "webpack": "^5.0.0" + } + }, + "node_modules/stylus/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/stylus/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/stylus/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/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, + "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, + "engines": { + "node": ">= 10" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.12.tgz", + "integrity": "sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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/test-exclude/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "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-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/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "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/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "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/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "engines": { + "node": ">=0.10.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==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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/validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/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/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/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/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "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/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-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.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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==", + "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==", + "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==" + }, + "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/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": 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==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "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": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dependencies": { + "cliui": "^7.0.2", + "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.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "dependencies": { + "tslib": "^2.3.0" + } + } + }, + "dependencies": { + "@adobe/css-tools": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", + "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/architect": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.10.tgz", + "integrity": "sha512-/6YmPrgataj1jD2Uqd1ED+CG4DaZGacoeZd/89hH7hF76Nno8K18DrSOqJAEmDnOWegpSRGVLd0qP09IHmaG5w==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.10", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/build-angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.10.tgz", + "integrity": "sha512-VCeZAyq4uPCJukKInaSiD4i/GgxgcU4jFlLFQtoYNmaBS4xbPOymL19forRIihiV0dwNEa2L694vRTAPMBxIfw==", + "dev": true, + "requires": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/build-webpack": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.10", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild": "0.15.5", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.16", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.74.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.10.tgz", + "integrity": "sha512-h+2MaSY7QSvoJ3R+Hvin21jVCfPGOTLdASIUk4Jmq6J3y5BSku3KSSaV8dWoBOBkFCwQyPQMRjiHoHKLpC1K7g==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1402.10", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.10.tgz", + "integrity": "sha512-K4AO7mROTdbhQ7chtyQd6oPwmuL+BPUh+wn6Aq1qrmYJK4UZYFOPp8fi/Ehs8meCEeywtrssOPfrOE4Gsre9dg==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.10.tgz", + "integrity": "sha512-MMp31KpJTwKHisXOq+6VOXYApq97hZxFaFmZk396X5aIFTCELUwjcezQDk+u2nEs5iK/COUfnN3plGcfJxYhQA==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.10", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-eslint/builder": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.4.0.tgz", + "integrity": "sha512-AhAUFvSg0urtb6Lsowvuxwu6DMXUy0BPwrnfNOBGjRt9vG7F9kgXXAsm5DnIS0GNy/mLZ9mSfa86fv++1e0KUA==", + "dev": true, + "requires": {} + }, + "@angular-eslint/bundled-angular-compiler": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.4.0.tgz", + "integrity": "sha512-KMHPHd24s0HVvAP/DxSSqhYBWhwW8FgS/r0Uwv8eWpsIdc/z/Chd2ush2SgPchmmquAXTgOZsbEY7ZmW+XkJfQ==", + "dev": true + }, + "@angular-eslint/eslint-plugin": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.4.0.tgz", + "integrity": "sha512-2rZQ4mt7tEUW+lI5jjuj3HWaT4VQtWTG6+LDnmuUmx76m8hqQ7NvFUpOcNDofu5KbEVBP+oF2DA6wjoZOIuSOA==", + "dev": true, + "requires": { + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/utils": "5.43.0" + } + }, + "@angular-eslint/eslint-plugin-template": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.4.0.tgz", + "integrity": "sha512-d3GM/EU2iWzr+BrITwO4gBf9WfDfuOdTjfinV/zN84oXMFaK2ENo+IP6OEsD9hh36rdPps+m2gFGDdx+rTzBpg==", + "dev": true, + "requires": { + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/type-utils": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "aria-query": "5.1.3", + "axobject-query": "3.1.1" + } + }, + "@angular-eslint/schematics": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.4.0.tgz", + "integrity": "sha512-BrGkPug+CZQWOfmNRsJDrEtYJcxvzF/kLlV7RjvIN9Ky5TjUiJVCeafl3VY6COSY32tjlh2GvBdl1AQKWWovbA==", + "dev": true, + "requires": { + "@angular-eslint/eslint-plugin": "14.4.0", + "@angular-eslint/eslint-plugin-template": "14.4.0", + "ignore": "5.2.0", + "strip-json-comments": "3.1.1", + "tmp": "0.2.1" + }, + "dependencies": { + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + } + } + }, + "@angular-eslint/template-parser": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.4.0.tgz", + "integrity": "sha512-zq888KpQB0YTEK26mkKcT4fs8LDWWT1oAEXU8DrXhvkikS8XavTSHOWJye/bVZR4oJRFCF5YTJV75DEMcGNIpQ==", + "dev": true, + "requires": { + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "eslint-scope": "^7.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "@angular-eslint/utils": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.4.0.tgz", + "integrity": "sha512-dPHklAVfh+JfueDfXre9Xooq7p5bFyKO2Z6y1agYeofAgHCPIJOPx2AhtFPrOtsc4VXFFiyE9XbowlXh4ogoKQ==", + "dev": true, + "requires": { + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@typescript-eslint/utils": "5.43.0" + } + }, + "@angular/animations": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.11.tgz", + "integrity": "sha512-HOw8xecbKfs7A5Ezjf+BfXKvvwU7X8I0US5Ey6bOuLvpA3QVOGSLw9BeutY5Q2mPWiRgnNNQW+FOd8Pe9gEkpQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/cdk": { + "version": "14.2.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.7.tgz", + "integrity": "sha512-/tEsYaUbDSnfEmKVvAMramIptmhI67O+9STjOV0i+74XR2NospeK0fkbywIANu1n3w6AHGMotvRWJrjmbCElFg==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + } + } + }, + "@angular/cli": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.10.tgz", + "integrity": "sha512-gX9sAKOwq4lKdPWeABB7TzKDHdjQXvkUU8NmPJA6mEAVXvm3lhQtFvHDalZstwK8au2LY0LaXTcEtcKYOt3AXQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "@schematics/angular": "14.2.10", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.2", + "resolve": "1.22.1", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + } + }, + "@angular/common": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.11.tgz", + "integrity": "sha512-a5w7lz4SoUzCwSDnuUPnfbEYPA8ufFiXz44mOv48P4uIb78q3rZ/R/EyWD1O3yJPof0o8aPNKpKZzuRDv3Q8ow==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.11.tgz", + "integrity": "sha512-QD4tq37qqPxxNK4o0Pd7dJm06evwEPChV67S/ecX3S6UkSDp8lVoWKiVx9htp/5s4iydKZU4eGu9oTOMOLVdOw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler-cli": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.11.tgz", + "integrity": "sha512-ipIEgueW8bhxVSq6qlgndBLVRCJoTvk1he/TI3w34m2EnZY1ctgGGCm1VbB3XARh+irVesPVMIAxRtjYds7XOw==", + "requires": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + } + }, + "@angular/core": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.11.tgz", + "integrity": "sha512-4uEIA6ESMLt2f/ivKuVBpME0IbuFHWmpweN4dwJt83DfJBiBfpqdrFYZHz/Kbkh9cGCiP7L4/eKPRWTlAHehhw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/forms": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.11.tgz", + "integrity": "sha512-sItoA3/I8j/pf3zhv8sR37M5dAYUJpezv8rw2fTT2Y+nZJFUpkFWqX2N4qpMlPY0MP9OX++8K8/d2j0Lfi3wJQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/localize": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.2.11.tgz", + "integrity": "sha512-vrYv2f6BR1dKebZB+c0O4Arx7iGF1MqN4gHB+V5KHS7UPIc3YnoQn9LaFDRWWazjrXCvq1uf1Cb8qzzu19+lZQ==", + "requires": { + "@babel/core": "7.18.9", + "glob": "8.0.3", + "yargs": "^17.2.1" + }, + "dependencies": { + "@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@angular/platform-browser": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.11.tgz", + "integrity": "sha512-lGi9pF0Kf/GGrVKcfxxfStM2eMSluDTmbcYuVAX28iBn5XEdfsonrkfy2cnxUMnQ7nioMAZBNGOJHbQPKz4jwg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.11.tgz", + "integrity": "sha512-kjcZda+gcAiYd0I3mjLSr6xR/HkUCnmIMyqaFGoHnIDXI2c6wLDxi49pivrJFvUYJPfYAJ6GjlYTM6L9B3XSEQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/pwa": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-0.5.3.tgz", + "integrity": "sha512-htgdGgWHaAHRdGZ1qxkn/4bQZjx2np+A/oGtuN86z+/jWuY4S+lYfPjLQTmq5kZaZDQm+qm0TVvayCQFEAnagg==", + "requires": { + "@angular-devkit/core": "0.5.3", + "@angular-devkit/schematics": "0.5.3", + "@schematics/angular": "0.5.3", + "typescript": "~2.6.2" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.5.3.tgz", + "integrity": "sha512-dv4zIZ7Xc/vkio5FGHOxfSva/G9fU/w0uhF3vws3H5yjRVRgdmbQ22dTcLjVMPZBM359xy2KFK+4lFMGuEdLCw==", + "requires": { + "ajv": "~5.5.1", + "chokidar": "^1.7.0", + "rxjs": "^6.0.0-beta.3", + "source-map": "^0.5.6" + } + }, + "@angular-devkit/schematics": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.5.3.tgz", + "integrity": "sha512-sAXaxeizGyadRb1jTtsyBwAMVLcGsGrmQiUw2aEf56uxnEWNNIntY5xPxP3ya0XrgUgG6YdrSNMpHay6qPGtww==", + "requires": { + "@angular-devkit/core": "0.5.3", + "@ngtools/json-schema": "^1.1.0", + "rxjs": "^6.0.0-beta.3" + } + }, + "@schematics/angular": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.5.3.tgz", + "integrity": "sha512-RQ4DMA5lyJ5XtBLpFxFs0UkyStl1j4n0YAojm/MAGI3B7uKB8qTN0txYvCYrbBUPdGhZC8ic9qzUw9UAJfLfUA==", + "requires": { + "@angular-devkit/core": "0.5.3", + "@angular-devkit/schematics": "0.5.3", + "typescript": "~2.6.2" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha512-mk8fAWcRUOxY7btlLtitj3A45jOwSAxH4tOFOoEGbVsl6cL6pPMWUy7dwZ/canfj3QEdP6FHSnf/l1c6/WkzVg==", + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==" + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "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==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "typescript": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha512-L0QfAFYU8U/ucTqDptb0Hq67++OwqdSKDAAXmpaECxEkPOIpydxh4p0p9BRDG0kliZHFJBAWZDHR0nomxF/E7A==" + } + } + }, + "@angular/router": { + "version": "14.2.11", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.11.tgz", + "integrity": "sha512-AbnyKXabar2WsG3fL24O1xdwkcRhRKI7u2vc9D8bcp2ks5GOJNxfbtG2Z6PSO18vtDszQxwELRe2cOEe+0TmPQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==" + }, + "@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "requires": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "requires": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz", + "integrity": "sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.19.1", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + }, + "@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "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.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz", + "integrity": "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz", + "integrity": "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz", + "integrity": "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.19.1", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz", + "integrity": "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz", + "integrity": "sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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.18.6", + "@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-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@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" + } + }, + "@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", + "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "requires": { + "@babel/types": "^7.20.2", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/types": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, + "@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "requires": {} + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "dev": true, + "optional": true + }, + "@eslint/eslintrc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "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, + "requires": { + "argparse": "^2.0.1" + } + }, + "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 + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "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 + } + } + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@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 + }, + "@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, + "requires": { + "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" + } + }, + "@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 + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@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==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "peer": true + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-13.1.1.tgz", + "integrity": "sha512-R6qnmFKT2EwwijBHw7rUXqyo5W90OImHOv7BlsxMNnZLIksWIhqwU00k4UBTfRTnd6JsTPuj/co3MaP61ajILA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ngneat/svg-generator": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ngneat/svg-generator/-/svg-generator-6.0.0.tgz", + "integrity": "sha512-jHvkTlLyeNHcedVALyI0PiaLXt4CkLEW11FAsahXZTB8+v3McXquqqNAdHg1Gxyp1H1xvPDFf9j+KZ5xOIFJvw==", + "dev": true, + "requires": { + "camelcase": "6.2.0", + "chokidar": "3.5.3", + "commander": "9.4.1", + "cosmiconfig": "7.0.1", + "fs-extra": "10.1.0", + "glob": "8.0.3", + "lodash.kebabcase": "4.1.1", + "svgo": "2.8.0", + "typescript": "4.8.4" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@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" + } + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "@ngneat/svg-icon": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@ngneat/svg-icon/-/svg-icon-6.1.0.tgz", + "integrity": "sha512-9a3FuvhSBlJMBEk0HdESWWM5zReYE0VESjnwbNjLvEN64IaIjGk+mJlPzqX3y0WgBW8cx9+1/bnpAz/o+mHQhQ==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@ngtools/json-schema": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz", + "integrity": "sha512-6i322P+RDn7nFiqdKqGGfvjyhEN551o8NsKxE0/lBAXzu0kUA8wlWa8d/RU1+VJtQ0+GOKFc7xHmoKuw7gt+Lw==" + }, + "@ngtools/webpack": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz", + "integrity": "sha512-sLHapZLVub6mEz5b19tf1VfIV1w3tYfg7FNPLeni79aldxu1FbP1v2WmiFAnMzrswqyK0bhTtxrl+Z/CLKqyoQ==", + "dev": true, + "requires": {} + }, + "@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ngx-translate/http-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-7.0.0.tgz", + "integrity": "sha512-j+NpXXlcGVdyUNyY/qsJrqqeAdJdizCd+GKh3usXExSqy1aE9866jlAIL+xrfDU4w+LiMoma5pgE4emvFebZmA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@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, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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 + }, + "@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, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" + }, + "@schematics/angular": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.10.tgz", + "integrity": "sha512-YFTc/9QJdx422XcApizEcVLKoyknu8b9zHIlAepZCu7WkV8GPT0hvVEHQ7KBWys5aQ7pPZMT0JpZLeAz0F2xYQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "jsonc-parser": "3.1.0" + } + }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "@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 + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.0.3.tgz", + "integrity": "sha512-Opp1LvvEuZdk8fSSvchK2mZwhVrsNT0JgJE9Di6MjnaIpmEXM8TLCPPrVtNTYh8+5MPdY8j9bAHMu2SSfwpZJg==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz", + "integrity": "sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/type-utils": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.43.0.tgz", + "integrity": "sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/typescript-estree": "5.43.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz", + "integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz", + "integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz", + "integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz", + "integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "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" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz", + "integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/typescript-estree": "5.43.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz", + "integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.43.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, + "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, + "requires": {} + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "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, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "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 + }, + "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, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "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, + "requires": { + "deep-equal": "^2.0.5" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "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 + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + } + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "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, + "requires": { + "@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" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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 + }, + "bootstrap": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.2.tgz", + "integrity": "sha512-dEtzMTV71n6Fhmbg4fYJzQsw1N29hJKO1js5ackCgIpDcGid2ETMGC6zwSYw09v05Y+oRdQ9loC54zB1La3hHQ==", + "requires": {} + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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 + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chart.js": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz", + "integrity": "sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==", + "peer": true, + "requires": { + "@kurkle/color": "^0.3.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "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==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "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==" + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "core-js-compat": { + "version": "3.26.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.1.tgz", + "integrity": "sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==", + "dev": true, + "requires": { + "browserslist": "^4.21.4" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@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" + } + }, + "critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + } + }, + "css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "requires": {} + }, + "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, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "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, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "dependencies": { + "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 + } + } + }, + "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 + }, + "cssdb": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.1.0.tgz", + "integrity": "sha512-Sd99PrFgx28ez4GHu8yoQIufc/70h9oYowDf4EjeIKi8mac9whxRjhM3IaMr6EllP6KKKWtJrMfN6C7T9tIWvQ==", + "dev": true + }, + "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 + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==" + }, + "deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "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 + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "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, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "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==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dev": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + } + }, + "engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, + "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, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "optional": true, + "requires": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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==" + }, + "eslint": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "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 + }, + "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, + "requires": { + "argparse": "^2.0.1" + } + }, + "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 + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + }, + "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 + } + } + }, + "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, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "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 + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "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 + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "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, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==", + "requires": { + "is-extglob": "^1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + } + } + }, + "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 + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@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" + } + }, + "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==" + }, + "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 + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "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, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "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, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "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, + "requires": { + "is-callable": "^1.1.3" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", + "requires": { + "for-in": "^1.0.1" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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 + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "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==" + }, + "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==" + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "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 + }, + "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 + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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 + }, + "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==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "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 + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "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 + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "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, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "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 + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "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, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true + }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, + "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, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "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 + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true + }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "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, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "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 + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "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==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "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, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "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 + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "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, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==", + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "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==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "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 + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "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, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==" + }, + "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, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "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 + }, + "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 + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "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, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "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 + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "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, + "requires": { + "@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" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "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 + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jasmine-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.3.0.tgz", + "integrity": "sha512-qybtBUesniQdW6n+QIHMng2vDOHscIC/dEXjW+JzO9+LoAZMb03RCUC5xFOv/btSKPm1xL42fn+RjlU4oB42Lg==", + "dev": true + }, + "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, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "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 + }, + "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 + }, + "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 + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "karma": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", + "integrity": "sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "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 + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "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" + } + }, + "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 + } + } + }, + "karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "requires": { + "which": "^1.2.1" + } + }, + "karma-coverage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "requires": { + "jasmine-core": "^4.1.0" + } + }, + "karma-jasmine-html-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", + "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", + "dev": true, + "requires": {} + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "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==" + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true + }, + "less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "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, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true + }, + "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, + "optional": true + } + } + }, + "less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "requires": { + "klona": "^2.0.4" + } + }, + "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, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "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 + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true + }, + "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, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "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==" + }, + "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 + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "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 + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + } + }, + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true + }, + "magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "requires": { + "object-visit": "^1.0.0" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, + "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 + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.11.tgz", + "integrity": "sha512-GvsCITGAyDCxxsJ+X6prJexFQEhOCJaIlUbsAvjzSI5o5O7j2dle3jWvz5Z5aOdpOxW6ol3vI1+0ut+641F1+w==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "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 + }, + "mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "optional": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "ng2-charts": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz", + "integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==", + "requires": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + } + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-gyp": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.0.tgz", + "integrity": "sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "requires": { + "abbrev": "^1.0.0" + } + }, + "normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "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 + }, + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "dependencies": { + "npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^2.0.0" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true + } + } + }, + "npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + } + }, + "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, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "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, + "requires": { + "boolbase": "^1.0.0" + } + }, + "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==", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "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, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "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 + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "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, + "requires": { + "p-try": "^2.0.0" + } + }, + "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, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + } + } + }, + "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 + }, + "pacote": { + "version": "13.6.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "dev": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "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, + "requires": { + "@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" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "requires": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" + }, + "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 + }, + "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==" + }, + "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 + }, + "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 + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "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 + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "requires": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" + } + }, + "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, + "requires": { + "find-up": "^4.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" + }, + "postcss": { + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "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, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-properties": { + "version": "12.1.10", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.10.tgz", + "integrity": "sha512-U3BHdgrYhCrwTVcByFHs9EOBoqcKq4Lf3kXwbTi4hhq0qWhl/pDWq2THbv/ICX/Fl9KqeHBb8OVrTf2OaYF07A==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "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, + "requires": {} + }, + "postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "requires": {} + }, + "postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "requires": {} + }, + "postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + } + }, + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "requires": {} + }, + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "requires": {} + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-opacity-percentage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", + "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", + "dev": true + }, + "postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "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, + "requires": {} + }, + "postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "requires": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "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, + "requires": {} + }, + "postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "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 + }, + "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 + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==" + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "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 + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "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, + "requires": { + "pify": "^2.3.0" + } + }, + "read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "dependencies": { + "npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true + } + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "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 + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + }, + "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==" + }, + "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 + }, + "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 + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "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 + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "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 + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "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, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass": { + "version": "1.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "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==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "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 + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socket.io": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + } + }, + "socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "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 + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "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, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + }, + "streamroller": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "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==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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 + }, + "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 + }, + "stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "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 + }, + "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, + "requires": { + "@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" + }, + "dependencies": { + "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 + } + } + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tar": { + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.12.tgz", + "integrity": "sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "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, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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 + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "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==" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "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==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "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, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "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 + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + }, + "ua-parser-js": { + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "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 + }, + "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 + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" + } + } + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "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, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "requires": { + "typed-assert": "^1.0.8" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "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, + "requires": { + "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" + } + }, + "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, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "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==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "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==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "requires": { + "cliui": "^7.0.2", + "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.0.0" + } + }, + "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==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "requires": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/frontend/projects/admin/package.json b/frontend/projects/admin/package.json new file mode 100644 index 0000000000..945181718c --- /dev/null +++ b/frontend/projects/admin/package.json @@ -0,0 +1,71 @@ +{ + "name": "alfio-admin", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve --proxy-config proxy.config.json", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "lint": "ng lint", + "prestart": "npm run svg", + "prebuild": "npm run svg", + "svg": "svg-generator" + }, + "svgGenerator": { + "outputPath": "./src/app/svg", + "srcPath": "./src/assets/svg", + "svgoConfig": { + "plugins": [ + "removeDimensions", + "cleanupAttrs" + ] + } + }, + "private": true, + "dependencies": { + "@angular/animations": "^14.2.0", + "@angular/cdk": "^14.2.7", + "@angular/common": "^14.2.0", + "@angular/compiler": "^14.2.0", + "@angular/core": "^14.2.0", + "@angular/forms": "^14.2.0", + "@angular/platform-browser": "^14.2.0", + "@angular/platform-browser-dynamic": "^14.2.0", + "@angular/pwa": "^0.5.3", + "@angular/router": "^14.2.0", + "@ng-bootstrap/ng-bootstrap": "^13.1.1", + "@ngneat/svg-icon": "^6.1.0", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "@popperjs/core": "^2.10.2", + "bootstrap": "^5.2.0", + "ng2-charts": "^4.1.1", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.2.10", + "@angular-eslint/builder": "14.4.0", + "@angular-eslint/eslint-plugin": "14.4.0", + "@angular-eslint/eslint-plugin-template": "14.4.0", + "@angular-eslint/schematics": "14.4.0", + "@angular-eslint/template-parser": "14.4.0", + "@angular/cli": "~14.2.10", + "@angular/compiler-cli": "^14.2.0", + "@angular/localize": "^14.2.0", + "@ngneat/svg-generator": "^6.0.0", + "@types/jasmine": "~4.0.0", + "@typescript-eslint/eslint-plugin": "5.43.0", + "@typescript-eslint/parser": "5.43.0", + "eslint": "^8.28.0", + "jasmine-core": "~4.3.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.0.0", + "typescript": "~4.7.2" + } +} \ No newline at end of file diff --git a/frontend/projects/admin/proxy.config.json b/frontend/projects/admin/proxy.config.json new file mode 100644 index 0000000000..a708abab83 --- /dev/null +++ b/frontend/projects/admin/proxy.config.json @@ -0,0 +1,32 @@ +{ + "/authentication-status": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + "/authenticate": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + "/admin/api": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + "/api/v2/": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + "/file": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + } +} diff --git a/frontend/projects/admin/src/app/access-control/access-control.component.html b/frontend/projects/admin/src/app/access-control/access-control.component.html new file mode 100644 index 0000000000..46e0673e93 --- /dev/null +++ b/frontend/projects/admin/src/app/access-control/access-control.component.html @@ -0,0 +1 @@ +

access-control works!

diff --git a/frontend/projects/admin/src/app/access-control/access-control.component.scss b/frontend/projects/admin/src/app/access-control/access-control.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/access-control/access-control.component.ts b/frontend/projects/admin/src/app/access-control/access-control.component.ts new file mode 100644 index 0000000000..6101158ba7 --- /dev/null +++ b/frontend/projects/admin/src/app/access-control/access-control.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-access-control', + templateUrl: './access-control.component.html', + styleUrls: ['./access-control.component.scss'] +}) +export class AccessControlComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.html b/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.html new file mode 100644 index 0000000000..2c2c3a1791 --- /dev/null +++ b/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.html @@ -0,0 +1,108 @@ +
+

Bulk creation

+
+
+ +
+
+
+ + +
+ +
+ + +
+
+
+

File Specifications:

+
General
+ Please create a CSV file without header, using commas (,) as separator, + double quotes (") as quote character and backslash (\) as escaping + character +
Row specification
+
+    name
+    where:
+    name
+    is the name of the client, to be displayed in the QR-Code and statistics
+  
+
+ +
+ + + + + + + + + + + + + + + + + +
Name
+ {{ description }} +
Total + {{ bulkDescriptions.length }} +
+ +
+
+ +
+
+ +
+
+
+
diff --git a/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.scss b/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.ts b/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.ts new file mode 100644 index 0000000000..9eed03db96 --- /dev/null +++ b/frontend/projects/admin/src/app/api-key-system-bulk/api-key-system-bulk.component.ts @@ -0,0 +1,67 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Organization } from '../model/organization'; +import { Observable, map } from 'rxjs'; +import { Role } from '../model/role'; +import { OrganizationService } from '../shared/organization.service'; +import { UserService } from '../shared/user.service'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-api-key-system-bulk', + templateUrl: './api-key-system-bulk.component.html', + styleUrls: ['./api-key-system-bulk.component.scss'], +}) +export class ApiKeySystemBulkComponent implements OnInit { + public organizations$?: Observable; + public roles$?: Observable; + public bulkForm: FormGroup; + + constructor( + private readonly route: ActivatedRoute, + private readonly organizationService: OrganizationService, + private readonly userService: UserService, + private readonly router: Router, + formBuilder: FormBuilder + ) { + this.bulkForm = formBuilder.group({ + organizationId: [null, Validators.required], + role: [null, Validators.required], + descriptions: [[]], + }); + } + + get bulkDescriptions(): string[] { + return this.bulkForm.value.descriptions; + } + + get userOrganizationId(){return this.bulkForm.get('organizationId')} + get userRole(){return this.bulkForm.get('role')} + + ngOnInit(): void { + this.organizations$ = this.organizationService.getOrganizations(); + this.roles$ = this.userService.getAllRoles(); + } + + save(): void { + this.userService.createApiBulk(this.bulkForm.value).subscribe((res) => { + if (res === 'OK') { + this.router.navigate(['/access-control/api-keys']); + } + }); + } + + onFileSelected(event: Event) { + const input = event.target as HTMLInputElement; + if (input && input.files) { + const file: File = input.files[0]; + file.text().then((res) => { + const descriptions = res + .split('\n') + .map((es) => es.trim()) + .filter((es) => es !== null && es.length > 0); + this.bulkForm.get('descriptions')?.patchValue(descriptions); + }); + } + } +} diff --git a/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.html b/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.html new file mode 100644 index 0000000000..6d5527c506 --- /dev/null +++ b/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.html @@ -0,0 +1,79 @@ +
+

+ +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+
+
+
diff --git a/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.scss b/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.ts b/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.ts new file mode 100644 index 0000000000..6c89cd1a40 --- /dev/null +++ b/frontend/projects/admin/src/app/api-key-system-edit/api-key-system-edit.component.ts @@ -0,0 +1,86 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Organization } from '../model/organization'; +import { Observable, map, of } from 'rxjs'; +import { User } from '../model/user'; +import { OrganizationService } from '../shared/organization.service'; +import { UserService } from '../shared/user.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Role } from '../model/role'; + +@Component({ + selector: 'app-api-key-system-edit', + templateUrl: './api-key-system-edit.component.html', + styleUrls: ['./api-key-system-edit.component.scss'], +}) +export class ApiKeySystemEditComponent implements OnInit { + public userForm: FormGroup; + public editMode: boolean | undefined; + public organizations$?: Observable; + public user$: Observable = of(); + public roles$?: Observable; + public userId: string | null = null; + + constructor( + formBuilder: FormBuilder, + private readonly organizationService: OrganizationService, + private readonly userService: UserService, + private readonly router: Router, + private readonly route: ActivatedRoute + ) { + this.userForm = formBuilder.group({ + id: [null], + organizationId: [null, Validators.required], + role: [null, Validators.required], + description: [null], + username: [null], + lastName: [null], + firstName: [null], + emailAddress: [null], + type: ['API_KEY'], + }); + } + get organizationDescription() { + return this.userForm.get('description'); + } + + get organizationName() { + return this.userForm.get('organizationId'); + } + + get role() { + return this.userForm.get('role'); + } + + ngOnInit(): void { + this.userId = this.route.snapshot.paramMap.get('userId'); + this.organizations$ = this.organizationService.getOrganizations(); + this.roles$ = this.userService.getAllRoles().pipe( + map((roles) => { + return roles.filter((role) => role.target.includes('USER')); + }) + ); + + if (this.userId !== null) { + this.editMode = true; + this.user$ = this.userService.getUser(this.userId); + this.user$.subscribe((user) => { + if (user) this.userForm.patchValue(user); + }); + } else { + this.editMode = false; + } + } + + save(): void { + let result: Observable; + if (this.editMode) { + result = this.userService.update(this.userForm.value); + } else { + result = this.userService.create(this.userForm.value); + } + result.subscribe((res) => { + this.router.navigate(['/access-control/api-keys']); + }); + } +} diff --git a/frontend/projects/admin/src/app/api-key-system/api-key-system.component.html b/frontend/projects/admin/src/app/api-key-system/api-key-system.component.html new file mode 100644 index 0000000000..6e8e4f3709 --- /dev/null +++ b/frontend/projects/admin/src/app/api-key-system/api-key-system.component.html @@ -0,0 +1,128 @@ +
+

+

+
+ +
+
+ +
+ +
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ / +
{{ user.username }} + + {{ org.description }} + + + {{ + roleDescription(role) | async + }} + + {{ + org.name + }} + view qr code + + + + + + +
+
+
diff --git a/frontend/projects/admin/src/app/api-key-system/api-key-system.component.scss b/frontend/projects/admin/src/app/api-key-system/api-key-system.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/api-key-system/api-key-system.component.ts b/frontend/projects/admin/src/app/api-key-system/api-key-system.component.ts new file mode 100644 index 0000000000..cbe84d3acd --- /dev/null +++ b/frontend/projects/admin/src/app/api-key-system/api-key-system.component.ts @@ -0,0 +1,75 @@ +import { Component, OnInit } from '@angular/core'; +import { UserService } from '../shared/user.service'; +import { Observable, map, of, shareReplay } from 'rxjs'; +import { RoleType, User } from '../model/user'; +import { Organization } from '../model/organization'; +import { Role } from '../model/role'; + +@Component({ + selector: 'app-api-key-system', + templateUrl: './api-key-system.component.html', + styleUrls: ['./api-key-system.component.scss'], +}) +export class ApiKeySystemComponent implements OnInit { + public users$?: Observable; + public organizations$?: Observable; + public roles$: Observable> = of(); + public selectedOrganization?: Organization; + + constructor(private readonly userService: UserService) {} + + ngOnInit(): void { + this.loadApiKey(); + this.roles$ = this.userService.getAllRoles().pipe( + map((roles) => { + const map: Map = new Map(); + roles.forEach((role) => { + map.set(role.role, role); + }); + return map; + }), + shareReplay(1) + ); + } + + private loadApiKey() { + this.users$ = this.userService.getAllApiKey(); + this.users$.subscribe((users) => { + const orgIdToOrg = new Map(); + users.forEach((user) => { + user.memberOf.forEach((org) => { + orgIdToOrg.set(org.id, org); + }); + }); + + const organizations = Array.from(orgIdToOrg.values()); + this.organizations$ = of(organizations); + }); + } + + roleDescription(role: RoleType): Observable { + return this.roles$.pipe(map((roles) => roles.get(role)?.description)); + } + + enable(user: User) { + this.userService.enable(user, !user.enabled).subscribe((result) => { + this.loadApiKey(); + }); + } + + deleteUserApikey(user: User) { + if ( + window.confirm( + `The apikey ${user.username} will be deleted. Are you sure?` + ) + ) { + this.userService.deleteUser(user).subscribe((result) => { + this.loadApiKey(); + }); + } + } + + downloadAllApiKeys(orgId: number) { + window.open(`/admin/api/api-keys/organization/${orgId}/all`); + } +} diff --git a/frontend/projects/admin/src/app/app-routing.module.ts b/frontend/projects/admin/src/app/app-routing.module.ts new file mode 100644 index 0000000000..b29394ba70 --- /dev/null +++ b/frontend/projects/admin/src/app/app-routing.module.ts @@ -0,0 +1,85 @@ +import { NgModule } from '@angular/core'; +import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; +import { MissingOrgComponent } from './missing-org/missing-org.component'; +import { OrganizationsComponent } from './organizations/organizations.component'; +import { OrganizationEditComponent } from './organization-edit/organization-edit.component'; +import { AccessControlComponent } from './access-control/access-control.component'; +import { UserSystemComponent } from './user-system/user-system.component'; +import { UserSystemEditComponent } from './user-system-edit/user-system-edit.component'; +import { ApiKeySystemEditComponent } from './api-key-system-edit/api-key-system-edit.component'; +import { ApiKeySystemBulkComponent } from './api-key-system-bulk/api-key-system-bulk.component'; +import { ApiKeySystemComponent } from './api-key-system/api-key-system.component'; + +const routes: Routes = [ + { + path: 'organization/:organizationId/event/:eventId', + loadChildren: () => + import('./event/event.module').then((m) => m.EventModule), + }, + { + path: 'organization/:organizationId', + loadChildren: () => + import('./dashboard/dashboard.module').then((m) => m.DashboardModule), + }, + { + path: 'authentication', + loadChildren: () => + import('./authentication/authentication.module').then( + (m) => m.AuthenticationModule + ), + }, + { + path: 'organizations', + component: OrganizationsComponent, + }, + { + path: 'organizations/new', + component: OrganizationEditComponent, + }, + { + path: 'organizations/:organizationId/edit', + component: OrganizationEditComponent, + }, + { + path: 'access-control', + component: AccessControlComponent, + }, + { + path: 'access-control/users', + component: UserSystemComponent, + }, + { + path: 'access-control/users/new', + component: UserSystemEditComponent, + }, + { + path: 'access-control/users/:userId/edit', + component: UserSystemEditComponent, + }, + { path: 'access-control/api-keys', component: ApiKeySystemComponent }, + { + path: 'access-control/api-keys/new', + component: ApiKeySystemEditComponent, + }, + { + path: 'access-control/api-keys/:userId/edit', + component: ApiKeySystemEditComponent, + }, + { + path: 'access-control/api-keys/bulk', + component: ApiKeySystemBulkComponent, + }, + { + path: '', + component: MissingOrgComponent, + pathMatch: 'full', + }, +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }), + ], + exports: [RouterModule], +}) +export class AppRoutingModule {} diff --git a/frontend/projects/admin/src/app/app.component.html b/frontend/projects/admin/src/app/app.component.html new file mode 100644 index 0000000000..675f96d6dc --- /dev/null +++ b/frontend/projects/admin/src/app/app.component.html @@ -0,0 +1,86 @@ + + +
+
+ +
+ +
+
+
diff --git a/frontend/projects/admin/src/app/app.component.scss b/frontend/projects/admin/src/app/app.component.scss new file mode 100644 index 0000000000..ed3615d9b8 --- /dev/null +++ b/frontend/projects/admin/src/app/app.component.scss @@ -0,0 +1,81 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/variables"; + +:host { + --header-height: 58px; +} + +header { + height: var(--header-height); +} + +/* + * Sidebar + */ + +.sidebar { + position: fixed; + top: 0; + /* rtl:raw: + right: 0; + */ + bottom: 0; + /* rtl:remove */ + left: 0; + z-index: 100; /* Behind the navbar */ + padding: var(--header-height) 0 0; /* Height of navbar */ + box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1); +} + +.sidebar-sticky { + height: calc(100vh - var(--header-height)); + overflow-x: hidden; + overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ +} + +$sidebarWidth: 76px; + +nav#sidebarMenu { + @include media-breakpoint-up(md) { + width: $sidebarWidth; + } + + a { + text-decoration: none; + color: $text-muted; + font-size: 70%; + font-weight: normal; + text-align: center; + margin-bottom: 1rem; + + &.active { + color: $primary; + font-weight: bold; + } + + &:hover { + color: $primary; + } + + svg-icon, + svg { + display: flex; + align-self: center; + } + } +} + +main { + @include media-breakpoint-up(md) { + width: calc(100% - $sidebarWidth); + } +} + +@include media-breakpoint-up(md) { + .profile-menu-container .dropdown-menu[data-bs-popper] { + width: 100%; + right: 0; + left: unset; + } +} diff --git a/frontend/projects/admin/src/app/app.component.ts b/frontend/projects/admin/src/app/app.component.ts new file mode 100644 index 0000000000..9304cca9f3 --- /dev/null +++ b/frontend/projects/admin/src/app/app.component.ts @@ -0,0 +1,72 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivationEnd, Router } from '@angular/router'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { combineLatest, filter, map, Observable, of } from 'rxjs'; +import { Organization } from './model/organization'; +import { UserInfo } from './model/user'; +import { OrgSelectorComponent } from './org-selector/org-selector.component'; +import { OrganizationService } from './shared/organization.service'; +import { UserService } from './shared/user.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], +}) +export class AppComponent implements OnInit { + public organizations$?: Observable; + public organizationId$?: Observable; + public currentUser$?: Observable; + public currentOrganization$?: Observable; + + constructor( + private readonly translateService: TranslateService, + private readonly organizationService: OrganizationService, + private readonly userService: UserService, + private readonly router: Router, + private readonly modalService: NgbModal + ) {} + + ngOnInit(): void { + this.translateService.setDefaultLang('en'); + this.translateService.use('en'); + this.organizations$ = this.organizationService.getOrganizations(); + this.organizationId$ = this.router.events.pipe( + filter((a) => a instanceof ActivationEnd), + map((a) => { + const ae = a as ActivationEnd; + return ae.snapshot.params['organizationId']; + }) + ); + this.currentUser$ = this.userService.getCurrent(); + this.currentOrganization$ = combineLatest([ + this.organizationId$, + this.organizations$, + ]).pipe( + map(([id, orgs]) => + orgs.find((o) => id !== null && o.id === Number.parseInt(id)) + ) + ); + } + + public openOrgSelector(): void { + const modalRef = this.modalService.open(OrgSelectorComponent, { + size: 'lg', + }); + const selector: OrgSelectorComponent = modalRef.componentInstance; + selector.organizations$ = this.organizations$; + selector.organizationId$ = this.organizationId$; + modalRef.result + .then((res: Organization) => { + this.router.navigate(['/organization', res.id, 'event']).then((r) => { + if (r) { + this.currentOrganization$ = of(res); + } + }); + }) + .catch(() => { + // we do nothing on dismiss + }); + } +} diff --git a/frontend/projects/admin/src/app/app.module.ts b/frontend/projects/admin/src/app/app.module.ts new file mode 100644 index 0000000000..4cfd2e5491 --- /dev/null +++ b/frontend/projects/admin/src/app/app.module.ts @@ -0,0 +1,110 @@ +import { + HTTP_INTERCEPTORS, + HttpClient, + HttpClientModule, + HttpClientXsrfModule, +} from '@angular/common/http'; +import { APP_INITIALIZER, NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { Router } from '@angular/router'; +import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; +import { SvgIconComponent, provideSvgIconsConfig } from '@ngneat/svg-icon'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { AlfioCommonModule } from 'common'; +import { firstValueFrom } from 'rxjs'; +import { AccessControlComponent } from './access-control/access-control.component'; +import { ApiKeySystemBulkComponent } from './api-key-system-bulk/api-key-system-bulk.component'; +import { ApiKeySystemEditComponent } from './api-key-system-edit/api-key-system-edit.component'; +import { ApiKeySystemComponent } from './api-key-system/api-key-system.component'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { AuthenticationModule } from './authentication/authentication.module'; +import { MissingOrgComponent } from './missing-org/missing-org.component'; +import { OrgSelectorComponent } from './org-selector/org-selector.component'; +import { OrganizationEditComponent } from './organization-edit/organization-edit.component'; +import { OrganizationsComponent } from './organizations/organizations.component'; +import { + HttpLoginInterceptor, + redirectToLogin, +} from './shared/http-login.interceptor'; +import { CustomLoader } from './shared/i18n.service'; +import { ICON_CONFIG } from './shared/icons'; +import { OrganizationService } from './shared/organization.service'; +import { SectionDashboardComponent } from './shared/section-dashboard/section-dashboard.component'; +import { SharedModule } from './shared/shared.module'; +import { UserService } from './shared/user.service'; +import { UserSystemEditComponent } from './user-system-edit/user-system-edit.component'; +import { UserSystemComponent } from './user-system/user-system.component'; + +export function RedirectToLoginIfNeeded( + userService: UserService, + router: Router +): () => Promise { + return async () => { + const loggedIn = await firstValueFrom(userService.checkUserLoggedIn()); + if (!loggedIn) { + return redirectToLogin(router); + } + return true; + }; +} + +// AoT requires an exported function for factories +export function HttpLoaderFactory(http: HttpClient) { + return new CustomLoader(http); +} + +@NgModule({ + declarations: [ + AppComponent, + MissingOrgComponent, + OrgSelectorComponent, + OrganizationsComponent, + OrganizationEditComponent, + AccessControlComponent, + UserSystemComponent, + UserSystemEditComponent, + ApiKeySystemComponent, + ApiKeySystemEditComponent, + ApiKeySystemBulkComponent, + ], + imports: [ + BrowserModule, + AppRoutingModule, + AuthenticationModule, + HttpClientModule, + ReactiveFormsModule, + FormsModule, + HttpClientXsrfModule.withOptions({ + cookieName: 'XSRF-TOKEN', + headerName: 'X-CSRF-TOKEN', + }), + SvgIconComponent, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient], + }, + }), + NgbDropdownModule, + SharedModule, + AlfioCommonModule, + ], + providers: [ + { + provide: APP_INITIALIZER, + useFactory: RedirectToLoginIfNeeded, + deps: [UserService, Router], + multi: true, + }, + { provide: HTTP_INTERCEPTORS, useClass: HttpLoginInterceptor, multi: true }, + provideSvgIconsConfig(ICON_CONFIG), + UserService, + OrganizationService, + ], + exports: [SectionDashboardComponent], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/frontend/projects/admin/src/app/authentication/authentication.component.html b/frontend/projects/admin/src/app/authentication/authentication.component.html new file mode 100644 index 0000000000..085c05de63 --- /dev/null +++ b/frontend/projects/admin/src/app/authentication/authentication.component.html @@ -0,0 +1,4 @@ +
+

Authentication requested

+

Please authenticate on the backend before continuing

+
diff --git a/frontend/projects/admin/src/app/authentication/authentication.component.ts b/frontend/projects/admin/src/app/authentication/authentication.component.ts new file mode 100644 index 0000000000..e12472ffbf --- /dev/null +++ b/frontend/projects/admin/src/app/authentication/authentication.component.ts @@ -0,0 +1,8 @@ +import {Component} from "@angular/core"; + +@Component({ + selector: 'app-authentication', + templateUrl: './authentication.component.html' +}) +export class AuthenticationComponent { +} diff --git a/frontend/projects/admin/src/app/authentication/authentication.module.ts b/frontend/projects/admin/src/app/authentication/authentication.module.ts new file mode 100644 index 0000000000..958b7a0ba2 --- /dev/null +++ b/frontend/projects/admin/src/app/authentication/authentication.module.ts @@ -0,0 +1,22 @@ +import {NgModule} from "@angular/core"; +import {AuthenticationComponent} from "./authentication.component"; +import {ReactiveFormsModule} from "@angular/forms"; +import {RouterModule} from "@angular/router"; +import {HttpClientModule} from "@angular/common/http"; + +@NgModule({ + imports: [ + ReactiveFormsModule, + HttpClientModule, + RouterModule.forChild([ + { + path: '', + component: AuthenticationComponent + } + ]) + ], + declarations: [ + AuthenticationComponent + ] +}) +export class AuthenticationModule {} diff --git a/frontend/projects/admin/src/app/dashboard/dashboard.component.html b/frontend/projects/admin/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000000..29b1c428be --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/dashboard.component.html @@ -0,0 +1,64 @@ +
+
+

+
+ + +
+
+
+
+ + +
+ + +
+

+
    +
  • + +
  • +
+
+
+ + + +
diff --git a/frontend/projects/admin/src/app/dashboard/dashboard.component.ts b/frontend/projects/admin/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000000..a7dcfd0bdf --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,71 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { map, mergeMap, Observable, of } from 'rxjs'; +import { EventInfo } from '../model/event'; +import { EventService } from '../shared/event.service'; +import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { ExportDateSelectorComponent } from './export-date-selector/export-date-selector.component'; + +@Component({ + templateUrl: './dashboard.component.html', +}) +export class DashboardComponent implements OnInit { + public organizationId$: Observable = of(); + public activeEvents$: Observable = of(); + public expiredEvents$: Observable = of(); + public activeFilter: boolean = true; + public inactiveFilter: boolean = false; + + constructor( + route: ActivatedRoute, + private readonly eventService: EventService, + private readonly modalService: NgbModal + ) { + this.organizationId$ = route.paramMap.pipe( + map((pm) => pm.get('organizationId')) + ); + } + + public ngOnInit(): void { + this.activeEvents$ = this.loadActiveEvents(); // default + } + + private loadActiveEvents() { + return this.organizationId$.pipe( + mergeMap((orgId) => + orgId != null ? this.eventService.getActiveEvents(orgId) : [] + ) + ); + } + + private loadInactiveEvents() { + return this.organizationId$.pipe( + mergeMap((orgId) => + orgId != null ? this.eventService.getExpiredEvents(orgId) : [] + ) + ); + } + + public toggleActiveFilter(toggle: boolean): void { + this.activeFilter = toggle; + if (toggle) { + this.activeEvents$ = this.loadActiveEvents(); + } else { + this.activeEvents$ = of(); + } + } + + public toggleInactiveFilter(toggle: boolean): void { + this.inactiveFilter = toggle; + if (toggle) { + this.expiredEvents$ = this.loadInactiveEvents(); + } else { + this.expiredEvents$ = of(); + } + } + public openExportDateSelector(): void { + const modalRef = this.modalService.open(ExportDateSelectorComponent, { + size: 'lg', + }); + } +} diff --git a/frontend/projects/admin/src/app/dashboard/dashboard.module.ts b/frontend/projects/admin/src/app/dashboard/dashboard.module.ts new file mode 100644 index 0000000000..bd57c89813 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/dashboard.module.ts @@ -0,0 +1,52 @@ +import { NgModule } from '@angular/core'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { DashboardComponent } from './dashboard.component'; +import { RouterModule } from '@angular/router'; +import { OrganizationService } from '../shared/organization.service'; +import { CommonModule } from '@angular/common'; +import { EventService } from '../shared/event.service'; +import { OrganizationConfigurationComponent } from './organization-configuration/organization-configuration.component'; +import { provideSvgIconsConfig, SvgIconComponent } from '@ngneat/svg-icon'; +import { TranslateModule } from '@ngx-translate/core'; +import { ICON_CONFIG } from '../shared/icons'; +import { SubscriptionsComponent } from './subscriptions/subscriptions.component'; +import { OrganizationInfoComponent } from './organization-info/organization-info.component'; +import { GroupsComponent } from './groups/groups.component'; +import { FilterButtonComponent } from '../shared/filter-button/filter-button.component'; +import { EventItemComponent } from './event-item/event-item.component'; +import { ExportDateSelectorComponent } from './export-date-selector/export-date-selector.component'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; + +@NgModule({ + imports: [ + TranslateModule.forChild(), + CommonModule, + NgbModule, + RouterModule.forChild([ + { path: 'event', component: DashboardComponent }, + { path: 'configuration', component: OrganizationConfigurationComponent }, + { path: 'subscriptions', component: SubscriptionsComponent }, + { path: 'organization-info', component: OrganizationInfoComponent }, + { path: 'groups', component: GroupsComponent }, + ]), + SvgIconComponent, + FilterButtonComponent, + ReactiveFormsModule, + FormsModule, + ], + declarations: [ + DashboardComponent, + OrganizationConfigurationComponent, + SubscriptionsComponent, + OrganizationInfoComponent, + GroupsComponent, + EventItemComponent, + ExportDateSelectorComponent, + ], + providers: [ + OrganizationService, + EventService, + provideSvgIconsConfig(ICON_CONFIG), + ], +}) +export class DashboardModule {} diff --git a/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.html b/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.html new file mode 100644 index 0000000000..0ffb9fd7b1 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.html @@ -0,0 +1,52 @@ + diff --git a/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.scss b/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.scss new file mode 100644 index 0000000000..b8cd06c537 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.scss @@ -0,0 +1,5 @@ +.text-overflow { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.ts b/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.ts new file mode 100644 index 0000000000..0587ea356d --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/event-item/event-item.component.ts @@ -0,0 +1,19 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { EventInfo } from '../../model/event'; + +@Component({ + selector: 'app-event-item', + templateUrl: './event-item.component.html', + styleUrls: ['./event-item.component.scss'], +}) +export class EventItemComponent implements OnInit { + @Input() + public event: EventInfo | undefined; + + @Input() + showImage: boolean = true; + + constructor() {} + + ngOnInit(): void {} +} diff --git a/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.html b/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.html new file mode 100644 index 0000000000..1dafe888b4 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.html @@ -0,0 +1,78 @@ + + diff --git a/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.scss b/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.ts b/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.ts new file mode 100644 index 0000000000..f075ece92b --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/export-date-selector/export-date-selector.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/forms'; +import { FormGroup } from '@angular/forms'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-export-date-selector', + templateUrl: './export-date-selector.component.html', + styleUrls: ['./export-date-selector.component.scss'], +}) +export class ExportDateSelectorComponent implements OnInit { + public dateForm: FormGroup; + constructor( + private readonly modalService: NgbModal, + public activeModal: NgbActiveModal, + formBuilder: FormBuilder + ) { + this.dateForm = formBuilder.group({ + fromDate: [null, Validators.required], + toDate: [null, Validators.required], + }); + } + + get fromDate() { + return this.dateForm.get('fromDate'); + } + + get toDate() { + return this.dateForm.get('toDate'); + } + + ngOnInit(): void {} +} diff --git a/frontend/projects/admin/src/app/dashboard/groups/groups.component.html b/frontend/projects/admin/src/app/dashboard/groups/groups.component.html new file mode 100644 index 0000000000..41ad0f66d7 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/groups/groups.component.html @@ -0,0 +1 @@ +

groups works!

diff --git a/frontend/projects/admin/src/app/dashboard/groups/groups.component.scss b/frontend/projects/admin/src/app/dashboard/groups/groups.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/dashboard/groups/groups.component.ts b/frontend/projects/admin/src/app/dashboard/groups/groups.component.ts new file mode 100644 index 0000000000..54f33cf9e1 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/groups/groups.component.ts @@ -0,0 +1,15 @@ +import {Component, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-groups', + templateUrl: './groups.component.html', + styleUrls: ['./groups.component.scss'] +}) +export class GroupsComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.html b/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.html new file mode 100644 index 0000000000..b0dc87782d --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.html @@ -0,0 +1 @@ +

organization-configuration works!

diff --git a/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.scss b/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.ts b/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.ts new file mode 100644 index 0000000000..067d201870 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/organization-configuration/organization-configuration.component.ts @@ -0,0 +1,15 @@ +import {Component, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-organization-configuration', + templateUrl: './organization-configuration.component.html', + styleUrls: ['./organization-configuration.component.scss'] +}) +export class OrganizationConfigurationComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.html b/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.html new file mode 100644 index 0000000000..5cf34fe66b --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.html @@ -0,0 +1 @@ +

organization-info works!

diff --git a/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.scss b/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.ts b/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.ts new file mode 100644 index 0000000000..6cf39b8836 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/organization-info/organization-info.component.ts @@ -0,0 +1,15 @@ +import {Component, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-organization-info', + templateUrl: './organization-info.component.html', + styleUrls: ['./organization-info.component.scss'] +}) +export class OrganizationInfoComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.html b/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.html new file mode 100644 index 0000000000..a0996687a0 --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.html @@ -0,0 +1 @@ +

subscriptions works!

diff --git a/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.scss b/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.ts b/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.ts new file mode 100644 index 0000000000..d9b689c0ee --- /dev/null +++ b/frontend/projects/admin/src/app/dashboard/subscriptions/subscriptions.component.ts @@ -0,0 +1,15 @@ +import {Component, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-subscriptions', + templateUrl: './subscriptions.component.html', + styleUrls: ['./subscriptions.component.scss'] +}) +export class SubscriptionsComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/event/email-log/email-log.component.html b/frontend/projects/admin/src/app/event/email-log/email-log.component.html new file mode 100644 index 0000000000..8f60b113f6 --- /dev/null +++ b/frontend/projects/admin/src/app/event/email-log/email-log.component.html @@ -0,0 +1 @@ +

email-log works!

diff --git a/frontend/projects/admin/src/app/event/email-log/email-log.component.scss b/frontend/projects/admin/src/app/event/email-log/email-log.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/event/email-log/email-log.component.ts b/frontend/projects/admin/src/app/event/email-log/email-log.component.ts new file mode 100644 index 0000000000..3a55c133d0 --- /dev/null +++ b/frontend/projects/admin/src/app/event/email-log/email-log.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-email-log', + templateUrl: './email-log.component.html', + styleUrls: ['./email-log.component.scss'] +}) +export class EmailLogComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.html b/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.html new file mode 100644 index 0000000000..a1d4c85d4e --- /dev/null +++ b/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.html @@ -0,0 +1,812 @@ + +
+ +
+
+ +

{{ event.displayName }}

+
+
+
+
+
+
+
+
+
+ +
+ +
+ {{ + eventOrganizationInfo.event.soldTickets + + eventOrganizationInfo.event.checkedInTickets + }} +
+
+
+
+
+
+
+
+
+ +
+
+ {{ eventOrganizationInfo.event.pendingTickets }} +
+
+
+
+
+
+
+
+
+ +
+
+ {{ eventOrganizationInfo.event.grossIncome }} + {{ eventOrganizationInfo.event.currency }} +
+
+
+
+
+
+
+ + +
+ +
+ + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ {{ + (instanceSetting$ | async)?.baseUrl + + "/event/" + + eventOrganizationInfo.event.shortName + }} +
+
+
+ {{ eventOrganizationInfo.organization.name }} <{{ + eventOrganizationInfo.organization.email + }}> +
+
+
+ {{ eventOrganizationInfo.event.websiteUrl }} +
+
+
+ {{ eventOrganizationInfo.event.termsAndConditionsUrl }} +
+
+
+ {{ eventOrganizationInfo.event.privacyPolicyUrl }} +
+
+
+ {{ eventOrganizationInfo.event.location }} +
+
+
+ +
+
+
+ {{ eventOrganizationInfo.event.formattedBegin | date }} +
+
+
+ {{ eventOrganizationInfo.event.formattedEnd | date }} +
+
+
{{ eventOrganizationInfo.event.timeZone }}
+
+
+
+ + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + {{ + eventOrganizationInfo.event.regularPrice + | currency : eventOrganizationInfo.event.currency || "" + }} +
+
+
+ {{ + eventOrganizationInfo.event.allowedPaymentProxies + | translatePaymentProxies + }} + +
+
+
+ {{ eventOrganizationInfo.event.availableSeats }} +
+
+
+ {{ eventOrganizationInfo.event.vatPercentage | currency : "" }} +
+
+
+ {{ + eventOrganizationInfo.event.finalPrice + | currency : eventOrganizationInfo.event.currency || "" + }} +
+
+
+
+
+
+
+
+ +
+
+
+
+
+

+ + +

+

+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + {{ ticketCategory.name }} + +
+
+ + + +
+
+
+
+ +
+
+ + + + + +
+
+
+
+ + + . +
+
+ + +
+ + + + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
diff --git a/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.scss b/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.scss new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.scss @@ -0,0 +1 @@ + diff --git a/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.ts b/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.ts new file mode 100644 index 0000000000..2fd8e15211 --- /dev/null +++ b/frontend/projects/admin/src/app/event/event-dashboard/event-dashboard.component.ts @@ -0,0 +1,211 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {ChartConfiguration, ChartData, ChartOptions} from 'chart.js'; +import {map, Observable, of, switchMap} from 'rxjs'; +import {Event, EventInfo, EventOrganizationInfo, EventTicketsStatistics,} from '../../model/event'; +import {EventService} from '../../shared/event.service'; +import {formatDate} from '@angular/common'; +import {ConfigurationService} from '../../shared/configuration.service'; +import {InstanceSetting} from '../../model/instance-settings'; +import {TicketCategory, TicketCategoryFilter, TicketTokenStatus, UiTicketCategory} from '../../model/ticket-category'; + +@Component({ + selector: 'app-event-dashboard', + templateUrl: './event-dashboard.component.html', + styleUrls: ['./event-dashboard.component.scss'], +}) +export class EventDashboardComponent implements OnInit { + public eventId$: Observable = of(); + public event$: Observable = of(); + public eventOrganizationInfo$: Observable = + of(); + public eventTicketsStatistics$: Observable = + of(); + public instanceSetting$: Observable = of(); + + public pieChartOptions: ChartOptions<'pie'> = { + responsive: true, + + plugins: { + legend: { + display: true, + position: 'right', + }, + }, + }; + public pieChartData: ChartData<'pie', number[], string | string[]> = { + labels: [], + datasets: [ + { + data: [], + backgroundColor: [], + }, + ], + }; + + public lineChartData: ChartConfiguration<'line'>['data'] = { + labels: [], + datasets: [], + }; + public lineChartOptions: ChartOptions<'line'> = { + responsive: true, + maintainAspectRatio: false, + }; + public lineChartLegend = true; + + public categoryFilter: TicketCategoryFilter = { + active: true, + expired: false, + search: '', + }; + + constructor( + private readonly eventService: EventService, + private readonly route: ActivatedRoute, + private readonly configurationService: ConfigurationService + ) { + this.eventId$ = route.paramMap.pipe(map((pm) => pm.get('eventId'))); + this.instanceSetting$ = this.configurationService.loadInstanceSetting(); + + this.event$ = this.eventId$.pipe( + switchMap((eventId) => + eventId != null ? eventService.getEvent(eventId) : of() + ) + ); + + this.eventOrganizationInfo$ = this.event$.pipe( + switchMap((event) => + event != null ? eventService.getEventByShortName(event.shortName) : of() + ) + ); + + this.eventTicketsStatistics$ = this.event$.pipe( + switchMap((event) => + event != null + ? eventService.getTicketsStatistics(event.shortName) + : of() + ) + ); + + this.eventOrganizationInfo$.subscribe((eventOrganizationInfo) => { + const event = eventOrganizationInfo?.event; + if (!event) { + return; + } + this.loadPieData(event); + }); + + this.eventTicketsStatistics$.subscribe((eventTicketsStatistics) => { + if (!eventTicketsStatistics) { + return; + } + this.loadLineData(eventTicketsStatistics); + }); + } + + loadLineData(eventTicketsStatistics: EventTicketsStatistics) { + this.lineChartData = { + labels: eventTicketsStatistics.sold.map((item) => + formatDate(item.date, 'mediumDate', 'en') + ), + datasets: [ + { + data: eventTicketsStatistics.sold.map((item) => item.count), + label: 'Created Reservations', + borderColor: 'green', + backgroundColor: 'green', + }, + { + data: eventTicketsStatistics.reserved.map((item) => item.count), + label: 'Confirmed Reservations', + borderColor: 'orange', + backgroundColor: 'orange', + }, + ], + }; + } + + loadPieData(event: EventInfo) { + const pieData = [ + { + value: event.checkedInTickets, + name: 'Checked in', + backgroundColor: '#5cb85c', + meta: 'Checked in (' + event.checkedInTickets + ')', + }, + { + value: event.soldTickets, + name: 'Sold', + backgroundColor: '#f0ad4e', + meta: 'Sold (' + event.soldTickets + ')', + }, + { + value: event.pendingTickets + event.releasedTickets, + name: 'Pending', + backgroundColor: '#7670b7', + meta: + 'Pending (' + (event.pendingTickets + event.releasedTickets) + ')', + }, + { + value: event.notSoldTickets, + name: 'Reserved for categories', + backgroundColor: '#00C4FF', + meta: 'Reserved for categories (' + event.notSoldTickets + ')', + }, + { + value: event.notAllocatedTickets, + name: 'Not yet allocated', + backgroundColor: '#d9534f', + meta: 'Not yet allocated (' + event.notAllocatedTickets + ')', + }, + { + value: event.dynamicAllocation, + name: 'Available', + backgroundColor: '#428bca', + meta: 'Available (' + event.dynamicAllocation + ')', + }, + ].filter((item) => item.value > 0); + + this.pieChartData = { + labels: pieData.map((item) => item.name), + datasets: [ + { + data: pieData.map((item) => item.value), + backgroundColor: pieData.map((item) => item.backgroundColor), + }, + ], + }; + } + countExpired(ticketCategory: TicketCategory[]) { + return ticketCategory.filter((ticketCategory) => ticketCategory.expired) + .length; + } + countActive(ticketCategory: TicketCategory[]) { + return ticketCategory.filter((ticketCategory) => !ticketCategory.expired) + .length; + } + + getActualCapacity(ticketCategory: TicketCategory, event: EventInfo) { + return ticketCategory.bounded + ? ticketCategory.maxTickets + : event.dynamicAllocation + ticketCategory.soldTickets; + } + + toggleTokenViewCollapse(ticketCategory: UiTicketCategory) { + ticketCategory.tokenViewExpanded = !ticketCategory.tokenViewExpanded; + } + + openConfiguration(event: EventInfo, ticketCategory: TicketCategory) { + alert('TODO'); + } + + containsValidTokens(tokens: TicketTokenStatus[]) { + return tokens.every((token) => token.status !== 'WAITING'); + } + + unbindTickets(eventShortName: string, category: UiTicketCategory) { + this.eventService.unbindTickets(eventShortName, category); + } + + ngOnInit(): void {} +} diff --git a/frontend/projects/admin/src/app/event/event-menu/event-menu.component.html b/frontend/projects/admin/src/app/event/event-menu/event-menu.component.html new file mode 100644 index 0000000000..e068c0f869 --- /dev/null +++ b/frontend/projects/admin/src/app/event/event-menu/event-menu.component.html @@ -0,0 +1,132 @@ +
+
+
+ +
+ + + + + + + + + +
+
+
+ +
+ + + + + +
+
+
+
+

+ +
+
diff --git a/frontend/projects/admin/src/app/event/event-menu/event-menu.component.scss b/frontend/projects/admin/src/app/event/event-menu/event-menu.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/event/event-menu/event-menu.component.ts b/frontend/projects/admin/src/app/event/event-menu/event-menu.component.ts new file mode 100644 index 0000000000..e915ac0517 --- /dev/null +++ b/frontend/projects/admin/src/app/event/event-menu/event-menu.component.ts @@ -0,0 +1,15 @@ +import {Component, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-event-menu', + templateUrl: './event-menu.component.html', + styleUrls: ['./event-menu.component.scss'] +}) +export class EventMenuComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/event/event.module.ts b/frontend/projects/admin/src/app/event/event.module.ts new file mode 100644 index 0000000000..fb148989f7 --- /dev/null +++ b/frontend/projects/admin/src/app/event/event.module.ts @@ -0,0 +1,58 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { + NgbCarouselModule, + NgbDropdownModule, + NgbNavModule, + NgbTypeaheadModule, +} from '@ng-bootstrap/ng-bootstrap'; +import { provideSvgIconsConfig, SvgIconComponent } from '@ngneat/svg-icon'; +import { TranslateModule } from '@ngx-translate/core'; +import { NgChartsModule } from 'ng2-charts'; +import { EventService } from '../shared/event.service'; +import { ICON_CONFIG } from '../shared/icons'; +import { OrganizationService } from '../shared/organization.service'; +import { SharedModule } from '../shared/shared.module'; +import { EventDashboardComponent } from './event-dashboard/event-dashboard.component'; +import { EventMenuComponent } from './event-menu/event-menu.component'; +import { TranslatePaymentProxiesPipe } from './translate-payment-proxies.pipe'; +import { EmailLogComponent } from './email-log/email-log.component'; +import { ShowSelectedCategoriesPipe } from './show-selected-categories.pipe'; +import { UiCategoryBuilderPipe } from './ui-category-builder.pipe'; +import { FormsModule } from '@angular/forms'; +import { TicketCategoryDetailComponent } from './ticket-category-detail/ticket-category-detail.component'; + +@NgModule({ + declarations: [ + EventMenuComponent, + EventDashboardComponent, + TranslatePaymentProxiesPipe, + EmailLogComponent, + ShowSelectedCategoriesPipe, + UiCategoryBuilderPipe, + TicketCategoryDetailComponent, + ], + imports: [ + TranslateModule.forChild(), + CommonModule, + SvgIconComponent, + SharedModule, + NgChartsModule, + NgbCarouselModule, + NgbNavModule, + FormsModule, + NgbDropdownModule, + + RouterModule.forChild([ + { path: '', component: EventDashboardComponent }, + { path: 'email-log', component: EmailLogComponent }, + ]), + ], + providers: [ + OrganizationService, + EventService, + provideSvgIconsConfig(ICON_CONFIG), + ], +}) +export class EventModule {} diff --git a/frontend/projects/admin/src/app/event/show-selected-categories.pipe.ts b/frontend/projects/admin/src/app/event/show-selected-categories.pipe.ts new file mode 100644 index 0000000000..10e254d30c --- /dev/null +++ b/frontend/projects/admin/src/app/event/show-selected-categories.pipe.ts @@ -0,0 +1,30 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {TicketCategoryFilter, UiTicketCategory} from '../model/ticket-category'; + + +@Pipe({ + name: 'showSelectedCategories', + pure: false, +}) +export class ShowSelectedCategoriesPipe implements PipeTransform { + transform( + categories: UiTicketCategory[], + criteria: TicketCategoryFilter + ): UiTicketCategory[] { + if (criteria.active && criteria.expired && criteria.search === '') { + return categories; + } + return categories.filter((category) => { + const result = + (criteria.active && !category.expired) || + (criteria.expired && category.expired); + if (result && criteria.search !== '') { + return ( + category.name.toLowerCase().indexOf(criteria.search.toLowerCase()) > + -1 + ); + } + return result; + }); + } +} diff --git a/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.html b/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.html new file mode 100644 index 0000000000..3e6fafed66 --- /dev/null +++ b/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.html @@ -0,0 +1 @@ +

ticket-category-detail works!

diff --git a/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.scss b/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.ts b/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.ts new file mode 100644 index 0000000000..5134aec103 --- /dev/null +++ b/frontend/projects/admin/src/app/event/ticket-category-detail/ticket-category-detail.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-ticket-category-detail', + templateUrl: './ticket-category-detail.component.html', + styleUrls: ['./ticket-category-detail.component.scss'] +}) +export class TicketCategoryDetailComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/projects/admin/src/app/event/translate-payment-proxies.pipe.ts b/frontend/projects/admin/src/app/event/translate-payment-proxies.pipe.ts new file mode 100644 index 0000000000..0c15a5c04c --- /dev/null +++ b/frontend/projects/admin/src/app/event/translate-payment-proxies.pipe.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +const PAYMENT_PROXY_DESCRIPTIONS = { + STRIPE: 'Stripe: Credit cards', + ON_SITE: 'On site (cash) payment', + OFFLINE: 'Offline payment (bank transfer, invoice, etc.)', + PAYPAL: 'PayPal', + MOLLIE: + 'Mollie: Credit cards, iDEAL, Bancontact, ING Home Pay, Belfius, KBC/CBC, Przelewy24', + SAFERPAY: 'Saferpay By SIX Payments', +} as any; + +@Pipe({ + name: 'translatePaymentProxies', +}) +export class TranslatePaymentProxiesPipe implements PipeTransform { + transform(list: string[]): string[] { + return list.map((item) => + PAYMENT_PROXY_DESCRIPTIONS[item] ? PAYMENT_PROXY_DESCRIPTIONS[item] : item + ); + } +} diff --git a/frontend/projects/admin/src/app/event/ui-category-builder.pipe.ts b/frontend/projects/admin/src/app/event/ui-category-builder.pipe.ts new file mode 100644 index 0000000000..bfc235e3f3 --- /dev/null +++ b/frontend/projects/admin/src/app/event/ui-category-builder.pipe.ts @@ -0,0 +1,12 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {TicketCategory, UiTicketCategory} from '../model/ticket-category'; + + +@Pipe({ + name: 'uiCategoryBuilder', +}) +export class UiCategoryBuilderPipe implements PipeTransform { + transform(categories: TicketCategory[]): UiTicketCategory[] { + return categories.map((category) => new UiTicketCategory(category)); + } +} diff --git a/frontend/projects/admin/src/app/missing-org/missing-org.component.html b/frontend/projects/admin/src/app/missing-org/missing-org.component.html new file mode 100644 index 0000000000..cfd93db722 --- /dev/null +++ b/frontend/projects/admin/src/app/missing-org/missing-org.component.html @@ -0,0 +1 @@ +

missing-org works!

diff --git a/frontend/projects/admin/src/app/missing-org/missing-org.component.scss b/frontend/projects/admin/src/app/missing-org/missing-org.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/missing-org/missing-org.component.ts b/frontend/projects/admin/src/app/missing-org/missing-org.component.ts new file mode 100644 index 0000000000..9b1f3c15dd --- /dev/null +++ b/frontend/projects/admin/src/app/missing-org/missing-org.component.ts @@ -0,0 +1,25 @@ +import {Component, OnInit} from '@angular/core'; +import {Router} from '@angular/router'; +import {firstValueFrom} from 'rxjs'; +import {OrganizationService} from '../shared/organization.service'; + +@Component({ + selector: 'app-missing-org', + templateUrl: './missing-org.component.html', + styleUrls: ['./missing-org.component.scss'] +}) +export class MissingOrgComponent implements OnInit { + + constructor( + private readonly organizationService: OrganizationService, + private readonly router: Router + ) { } + + ngOnInit(): void { + firstValueFrom(this.organizationService.getOrganizations()).then(orgs => { + if (orgs.length > 0) { + this.router.navigate(['organization', orgs[0].id, 'event']); + } + }); + } +} diff --git a/frontend/projects/admin/src/app/model/apikey-bulk.ts b/frontend/projects/admin/src/app/model/apikey-bulk.ts new file mode 100644 index 0000000000..afdbe34227 --- /dev/null +++ b/frontend/projects/admin/src/app/model/apikey-bulk.ts @@ -0,0 +1,5 @@ +export interface ApiKeyBulk{ + organizationId : number; + role: string; + descriptions: string[]; +} diff --git a/frontend/projects/admin/src/app/model/event.ts b/frontend/projects/admin/src/app/model/event.ts new file mode 100644 index 0000000000..4dc2b4ec03 --- /dev/null +++ b/frontend/projects/admin/src/app/model/event.ts @@ -0,0 +1,70 @@ +import {Organization} from './organization'; +import {TicketCategory} from './ticket-category'; + +export interface EventInfo { + allowedPaymentProxies: string[]; // TODO: enum + availableSeats: number; + checkedInTickets: number; + currency: string; + description: { [lang: string]: string }; + displayName: string; + displayStatistics: boolean; + displayLanguage: string; + contentLanguages: { + displayLanguage: string; + language: string; + }[]; + dynamicAllocation: number; + expired: boolean; + fileBlobId: string; + formattedBegin: string; + formattedEnd: string; + freeOfCharge: boolean; + id: number; + location: string; + notAllocatedTickets: number; + notSoldTickets: number; + organizationId: number; + online: boolean; + pendingTickets: number; + privacyPolicyUrl: string; + releasedTickets: number; + shortName: string; + soldTickets: number; + status: string; // TODO: enum + termsAndConditionsUrl: string; + timeZone: string; + visibleForCurrentUser: boolean; + warningNeeded: boolean; + websiteUrl: string; + grossIncome: number; + regularPrice: number; + finalPrice: number; + vatPercentage: number; + ticketCategories: TicketCategory[]; + format: string; + containingUnboundedCategories: boolean; +} + +export interface EventOrganizationInfo { + event: EventInfo; + organization: Organization; +} + +export interface Event { + id: number; + displayName: string; + shortName: string; +} + +export interface EventTicketsStatistics { + granularity: string; + sold: { + count: number; + date: string; + }[]; + reserved: { + count: number; + date: string; + }[]; +} diff --git a/frontend/projects/admin/src/app/model/instance-settings.ts b/frontend/projects/admin/src/app/model/instance-settings.ts new file mode 100644 index 0000000000..1cf4ce9e8d --- /dev/null +++ b/frontend/projects/admin/src/app/model/instance-settings.ts @@ -0,0 +1,4 @@ +export interface InstanceSetting { + descriptionMaxLength: number; + baseUrl: string; +} diff --git a/frontend/projects/admin/src/app/model/organization.ts b/frontend/projects/admin/src/app/model/organization.ts new file mode 100644 index 0000000000..ee9d7af32d --- /dev/null +++ b/frontend/projects/admin/src/app/model/organization.ts @@ -0,0 +1,8 @@ +export interface Organization { + id: number; + name: string; + description: string; + email: string; + externalId: string | null, + slug: string | null, +} diff --git a/frontend/projects/admin/src/app/model/role.ts b/frontend/projects/admin/src/app/model/role.ts new file mode 100644 index 0000000000..49bd0c5679 --- /dev/null +++ b/frontend/projects/admin/src/app/model/role.ts @@ -0,0 +1,7 @@ +import { RoleType } from "./user"; + +export interface Role { + role: RoleType; + target: string[]; + description: string; +} diff --git a/frontend/projects/admin/src/app/model/ticket-category.ts b/frontend/projects/admin/src/app/model/ticket-category.ts new file mode 100644 index 0000000000..665eac6b9c --- /dev/null +++ b/frontend/projects/admin/src/app/model/ticket-category.ts @@ -0,0 +1,116 @@ +export type TicketAccessType = 'INHERIT' | 'IN_PERSON' | 'ONLINE'; + +export interface TicketTokenStatus { + accessCodeId: number | null; + code: string; + id: number; + priceInCents: number; + recipientEmail: string | null; + recipientName: string | null; + sentTimestamp: string | null; + status: string; + ticketCategoryId: number; +} + +export interface TicketCategory { + accessRestricted: boolean; + availableTickets: number | null; + bounded: boolean; + checkedInTickets: number; + containingOrphans: boolean; + containingStuckTickets: boolean; + description: { [key: string]: string }; + displayTaxInformation: boolean; + expired: boolean; + formattedDiscountedPrice: string; + formattedExpiration: { [key: string]: string }; + formattedFinalPrice: string; + formattedInception: { [key: string]: string }; + free: boolean; + hasDiscount: boolean; + id: number; + maximumSaleableTickets: number; + maxTickets: number; + name: string; + notSoldTickets: number; + pendingTickets: number; + saleableAndLimitNotReached: boolean; + saleInFuture: boolean; + soldOutOrLimitReached: boolean; + soldTickets: number; + ticketAccessType: TicketAccessType; + tokenStatus: TicketTokenStatus[]; +} + +export class UiTicketCategory implements TicketCategory { + accessRestricted: boolean; + availableTickets: number | null; + bounded: boolean; + checkedInTickets: number; + containingOrphans: boolean; + containingStuckTickets: boolean; + description: { [key: string]: string }; + displayTaxInformation: boolean; + displayWarning: boolean; + expired: boolean; + formattedDiscountedPrice: string; + formattedExpiration: { [key: string]: string }; + formattedFinalPrice: string; + formattedInception: { [key: string]: string }; + free: boolean; + hasDiscount: boolean; + id: number; + maximumSaleableTickets: number; + maxTickets: number; + name: string; + notSoldTickets: number; + pendingTickets: number; + saleableAndLimitNotReached: boolean; + saleInFuture: boolean; + soldOutOrLimitReached: boolean; + soldTickets: number; + ticketAccessType: TicketAccessType; + tokenViewExpanded: boolean; + attendeesList: { groupId: number; groupName: string } | null; + tokenStatus: TicketTokenStatus[]; + + constructor(ticketCategory: TicketCategory) { + this.accessRestricted = ticketCategory.accessRestricted; + this.availableTickets = ticketCategory.availableTickets; + this.bounded = ticketCategory.bounded; + this.checkedInTickets = ticketCategory.checkedInTickets; + this.containingOrphans = ticketCategory.containingOrphans; + this.containingStuckTickets = ticketCategory.containingStuckTickets; + this.description = ticketCategory.description; + this.displayTaxInformation = ticketCategory.displayTaxInformation; + this.displayWarning = + ticketCategory.containingStuckTickets || ticketCategory.containingOrphans; + this.expired = ticketCategory.expired; + this.formattedDiscountedPrice = ticketCategory.formattedDiscountedPrice; + this.formattedExpiration = ticketCategory.formattedExpiration; + this.formattedFinalPrice = ticketCategory.formattedFinalPrice; + this.formattedInception = ticketCategory.formattedInception; + this.free = ticketCategory.free; + this.hasDiscount = ticketCategory.hasDiscount; + this.id = ticketCategory.id; + this.maximumSaleableTickets = ticketCategory.maximumSaleableTickets; + this.maxTickets = ticketCategory.maxTickets; + this.name = ticketCategory.name; + this.saleableAndLimitNotReached = ticketCategory.saleableAndLimitNotReached; + this.saleInFuture = ticketCategory.saleInFuture; + this.soldOutOrLimitReached = ticketCategory.soldOutOrLimitReached; + this.soldTickets = ticketCategory.soldTickets; + this.ticketAccessType = ticketCategory.ticketAccessType; + this.pendingTickets = ticketCategory.pendingTickets; + this.notSoldTickets = ticketCategory.notSoldTickets; + this.tokenStatus = ticketCategory.tokenStatus; + this.tokenViewExpanded = false; + this.attendeesList = null; + } +} + +export interface TicketCategoryFilter { + active: boolean; + expired: boolean; + search: string; +} diff --git a/frontend/projects/admin/src/app/model/user.ts b/frontend/projects/admin/src/app/model/user.ts new file mode 100644 index 0000000000..5bf3a02b38 --- /dev/null +++ b/frontend/projects/admin/src/app/model/user.ts @@ -0,0 +1,43 @@ +import { Organization } from "./organization"; + +export interface UserInfo { + id: number; + type: UserType; + username: string; + description: string; + firstName: string; + lastName: string; + emailAddress: string; + role: RoleType; +} + +export enum UserType { + INTERNAL = 'INTERNAL', + DEMO = 'DEMO', + API_KEY = 'API_KEY' +} + +export enum RoleType { + ADMIN = 'ADMIN', + OWNER = 'OWNER', + SUPERVISOR = 'SUPERVISOR', + OPERATOR = 'OPERATOR', + SPONSOR = 'SPONSOR', + API_CONSUMER = 'API_CONSUMER' +} + +export interface User { + id: number; + type: UserType; + enabled: boolean; + validTo: string | null; + username: string; + firstName: string; + lastName: string; + emailAddress: string; + validToEpochSecond: number | null; + description: string | null; + roles: RoleType[]; + memberOf: Organization[]; +} + diff --git a/frontend/projects/admin/src/app/org-selector/org-selector.component.html b/frontend/projects/admin/src/app/org-selector/org-selector.component.html new file mode 100644 index 0000000000..50ae90bd21 --- /dev/null +++ b/frontend/projects/admin/src/app/org-selector/org-selector.component.html @@ -0,0 +1,39 @@ + + + diff --git a/frontend/projects/admin/src/app/org-selector/org-selector.component.scss b/frontend/projects/admin/src/app/org-selector/org-selector.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/org-selector/org-selector.component.ts b/frontend/projects/admin/src/app/org-selector/org-selector.component.ts new file mode 100644 index 0000000000..1e4ee9b4d1 --- /dev/null +++ b/frontend/projects/admin/src/app/org-selector/org-selector.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Observable } from 'rxjs'; +import { Organization } from '../model/organization'; + +@Component({ + selector: 'app-org-selector', + templateUrl: './org-selector.component.html', + styleUrls: ['./org-selector.component.scss'], +}) +export class OrgSelectorComponent implements OnInit { + public organizations$?: Observable; + public organizationId$?: Observable; + + constructor(public activeModal: NgbActiveModal) {} + + ngOnInit(): void {} + + public selectOrganization(org: Organization): void { + this.activeModal.close(org); + } +} diff --git a/frontend/projects/admin/src/app/organization-edit/organization-edit.component.html b/frontend/projects/admin/src/app/organization-edit/organization-edit.component.html new file mode 100644 index 0000000000..4b359fa48c --- /dev/null +++ b/frontend/projects/admin/src/app/organization-edit/organization-edit.component.html @@ -0,0 +1,114 @@ +
+

+ + Edit organization {{ (organization$ | async)?.name }} +

+
+ +
+
+

+
+
+ + +
+
+ + +
+
+ + +
+

+
+
+ +
+
+ {{ (instanceSetting$ | async)?.baseUrl }}/o/ +
+ +
+ / +
+
+
+ + +
+
+
+
+ +
+
+ +
+
+
+
diff --git a/frontend/projects/admin/src/app/organization-edit/organization-edit.component.scss b/frontend/projects/admin/src/app/organization-edit/organization-edit.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/organization-edit/organization-edit.component.ts b/frontend/projects/admin/src/app/organization-edit/organization-edit.component.ts new file mode 100644 index 0000000000..30d935882b --- /dev/null +++ b/frontend/projects/admin/src/app/organization-edit/organization-edit.component.ts @@ -0,0 +1,81 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { OrganizationService } from '../shared/organization.service'; +import { Observable, of } from 'rxjs'; +import { Organization } from '../model/organization'; +import { ConfigurationService } from '../shared/configuration.service'; +import { InstanceSetting } from '../model/instance-settings'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { Validators } from '@angular/forms'; + +@Component({ + selector: 'app-organization-edit', + templateUrl: './organization-edit.component.html', + styleUrls: ['./organization-edit.component.scss'], +}) +export class OrganizationEditComponent implements OnInit { + public organizationId: string | null = null; + public organization$: Observable = of(); + public editMode: boolean | undefined; + public instanceSetting$: Observable = of(); + public organizationForm: FormGroup; + + constructor( + private readonly route: ActivatedRoute, + private readonly organizationService: OrganizationService, + private readonly configurationService: ConfigurationService, + formBuilder: FormBuilder, + private readonly router: Router + ) { + this.organizationForm = formBuilder.group({ + id: [null], + name: [null, Validators.required], + email: [null, Validators.required], + description: [null, Validators.required], + slug: [], + externalId: [], + }); + } + + get organizationName() { + return this.organizationForm.get('name'); + } + get organizationEmail() { + return this.organizationForm.get('email'); + } + get organizationDescription() { + return this.organizationForm.get('description'); + } + + ngOnInit(): void { + this.organizationId = this.route.snapshot.paramMap.get('organizationId'); + this.instanceSetting$ = this.configurationService.loadInstanceSetting(); + + if (this.organizationId !== null) { + this.editMode = true; + this.organization$ = this.organizationService.getOrganization( + this.organizationId + ); + this.organization$.subscribe((org) => { + if (org) this.organizationForm.patchValue(org); + }); + } else { + this.editMode = false; + } + } + + save(): void { + let result: Observable; + if (this.editMode) { + result = this.organizationService.update(this.organizationForm.value); + } else { + result = this.organizationService.create(this.organizationForm.value); + } + + result.subscribe((res) => { + if (res === 'OK') { + this.router.navigate(['/organizations']); + } + }); + } +} diff --git a/frontend/projects/admin/src/app/organizations/organizations.component.html b/frontend/projects/admin/src/app/organizations/organizations.component.html new file mode 100644 index 0000000000..07fb539c8a --- /dev/null +++ b/frontend/projects/admin/src/app/organizations/organizations.component.html @@ -0,0 +1,40 @@ +
+

+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + +
+ {{ org.name }} + {{ org.description }}{{ org.email }} + +
+
diff --git a/frontend/projects/admin/src/app/organizations/organizations.component.scss b/frontend/projects/admin/src/app/organizations/organizations.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/organizations/organizations.component.ts b/frontend/projects/admin/src/app/organizations/organizations.component.ts new file mode 100644 index 0000000000..f4c8be1487 --- /dev/null +++ b/frontend/projects/admin/src/app/organizations/organizations.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit } from '@angular/core'; +import { OrganizationService } from '../shared/organization.service'; +import { Observable } from 'rxjs'; +import { Organization } from '../model/organization'; + +@Component({ + selector: 'app-organizations', + templateUrl: './organizations.component.html', + styleUrls: ['./organizations.component.scss'], +}) +export class OrganizationsComponent implements OnInit { + public organizations$?: Observable; + + constructor(private readonly organizationService: OrganizationService) {} + + ngOnInit(): void { + this.organizations$ = this.organizationService.getOrganizations(); + } +} diff --git a/frontend/projects/admin/src/app/shared/configuration.service.ts b/frontend/projects/admin/src/app/shared/configuration.service.ts new file mode 100644 index 0000000000..b4aa801675 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/configuration.service.ts @@ -0,0 +1,17 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { InstanceSetting } from '../model/instance-settings'; + +@Injectable({ + providedIn: 'root', +}) +export class ConfigurationService { + constructor(private httpClient: HttpClient) {} + + loadInstanceSetting(): Observable { + return this.httpClient.get( + '/admin/api/configuration/instance-settings' + ); + } +} diff --git a/frontend/projects/admin/src/app/shared/event.service.ts b/frontend/projects/admin/src/app/shared/event.service.ts new file mode 100644 index 0000000000..1c7b5c819e --- /dev/null +++ b/frontend/projects/admin/src/app/shared/event.service.ts @@ -0,0 +1,55 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {map, Observable} from 'rxjs'; +import {Event, EventInfo, EventOrganizationInfo, EventTicketsStatistics,} from '../model/event'; +import {UiTicketCategory} from '../model/ticket-category'; + + +@Injectable() +export class EventService { + constructor(private httpClient: HttpClient) {} + + getActiveEvents(organizationId: string): Observable { + const orgId = parseInt(organizationId); + return this.httpClient + .get('/admin/api/active-events') + .pipe(map((events) => events.filter((e) => e.organizationId === orgId))); + } + + getExpiredEvents(organizationId: string): Observable { + const orgId = parseInt(organizationId); + return this.httpClient + .get('/admin/api/expired-events') + .pipe(map((events) => events.filter((e) => e.organizationId == orgId))); + } + + getEvent(eventId: string): Observable { + return this.httpClient.get(`/admin/api/events/id/${eventId}`); + } + + getEventByShortName( + eventShortName: string + ): Observable { + return this.httpClient.get( + `/admin/api/events/${eventShortName}` + ); + } + + getTicketsStatistics( + eventShortName: string + ): Observable { + return this.httpClient.get( + `/admin/api/events/${eventShortName}/ticket-sold-statistics` + ); + } + unbindTickets(eventShortName: string, category: UiTicketCategory) { + return this.httpClient.put( + '/admin/api/events/' + + eventShortName + + '/category/' + + category.id + + '/unbind-tickets', + null + ); + } +} diff --git a/frontend/projects/admin/src/app/shared/filter-button/filter-button.component.ts b/frontend/projects/admin/src/app/shared/filter-button/filter-button.component.ts new file mode 100644 index 0000000000..23a53b5e8b --- /dev/null +++ b/frontend/projects/admin/src/app/shared/filter-button/filter-button.component.ts @@ -0,0 +1,36 @@ +import {NgClass, NgIf} from '@angular/common'; +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {SvgIconComponent} from '@ngneat/svg-icon'; + +@Component({ + standalone: true, + imports: [SvgIconComponent, NgClass, NgIf], + selector: 'app-filter-button', + template: ` + `, +}) +export class FilterButtonComponent { + + @Input() + public text?: string; + + @Input() + public checked: boolean = false; + + @Output() + public toggleFilter = new EventEmitter(); + + constructor() { } + + public onClick(): void { + this.toggleFilter.emit(!this.checked); + } +} diff --git a/frontend/projects/admin/src/app/shared/http-login.interceptor.ts b/frontend/projects/admin/src/app/shared/http-login.interceptor.ts new file mode 100644 index 0000000000..10d5aee1d2 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/http-login.interceptor.ts @@ -0,0 +1,40 @@ +import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "@angular/common/http"; +import {catchError, Observable, throwError} from "rxjs"; +import {Inject, Injectable, Injector, INJECTOR} from "@angular/core"; +import {environment} from "../../environments/environment"; +import {Router} from "@angular/router"; + +@Injectable() +export class HttpLoginInterceptor implements HttpInterceptor { + + constructor(@Inject(INJECTOR) private injector: Injector) { + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + // set X-Requested-With to XMLHttpRequest to match checks on the backend + const clonedRequest = req.clone({ + headers: req.headers.set("X-Requested-With", "XMLHttpRequest") + }); + return next.handle(clonedRequest) + .pipe(catchError(err => { + if (err.status === 401) { + // user authentication is not valid anymore. + // let's redirect it to the authentication resource + redirectToLogin(this.injector.get(Router)).then(() => {}) + } + return throwError(() => err); + })); + } + +} + +export function redirectToLogin(router: Router): Promise { + if (environment.production) { + // reload the current location to trigger server-side authentication + window.location.reload(); + } else { + // dev mode: redirect to the /authentication local resource + return router.navigate(['./authentication']); + } + return Promise.resolve(true); +} diff --git a/frontend/projects/admin/src/app/shared/i18n.service.ts b/frontend/projects/admin/src/app/shared/i18n.service.ts new file mode 100644 index 0000000000..9938f7e716 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/i18n.service.ts @@ -0,0 +1,18 @@ +import {HttpClient} from "@angular/common/http"; +import {TranslateLoader} from "@ngx-translate/core"; +import {Observable, shareReplay} from "rxjs"; + +const translationCache: {[key: string]: Observable} = {}; + +export class CustomLoader implements TranslateLoader { + + constructor(private http: HttpClient) { + } + + getTranslation(lang: string): Observable { + if (!translationCache[lang]) { + translationCache[lang] = this.http.get(`/api/v2/admin/i18n/bundle/${lang}`).pipe(shareReplay(1)); + } + return translationCache[lang]; + } +} diff --git a/frontend/projects/admin/src/app/shared/icons.ts b/frontend/projects/admin/src/app/shared/icons.ts new file mode 100644 index 0000000000..7377ee53f3 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/icons.ts @@ -0,0 +1,98 @@ +import { accessIcon } from '../svg/access'; +import { accountcircleIcon } from '../svg/accountcircle'; +import { addIcon } from '../svg/add'; +import { addCircleNewIcon } from '../svg/add-circle-new'; +import { arrowBackIcon } from '../svg/arrow-back'; +import { arrowdropdownIcon } from '../svg/arrowdropdown'; +import { calendarEventIcon } from '../svg/calendar-event'; +import { categoryIcon } from '../svg/category'; +import { checkIcon } from '../svg/check'; +import { closeIcon } from '../svg/close'; +import { deleteIcon } from '../svg/delete'; +import { descriptionIcon } from '../svg/description'; +import { detailsIcon } from '../svg/details'; +import { downloadIcon } from '../svg/download'; +import { editIcon } from '../svg/edit'; +import { emailSentIcon } from '../svg/email-sent'; +import { eventIcon } from '../svg/event'; +import { groupsIcon } from '../svg/groups'; +import { homeIcon } from '../svg/home'; +import { hourglassTopIcon } from '../svg/hourglass-top'; +import { infoIcon } from '../svg/info'; +import { insightsIcon } from '../svg/insights'; +import { keyIcon } from '../svg/key'; +import { lockIcon } from '../svg/lock'; +import { lockOpenIcon } from '../svg/lock-open'; +import { organizationIcon } from '../svg/organization'; +import { outgoingMailIcon } from '../svg/outgoing-mail'; +import { paymentsIcon } from '../svg/payments'; +import { percentIcon } from '../svg/percent'; +import { piggyBankIcon } from '../svg/piggy-bank'; +import { qrCodeIcon } from '../svg/qr-code'; +import { resetIcon } from '../svg/reset'; +import { searchIcon } from '../svg/search'; +import { settingsIcon } from '../svg/settings'; +import { subscriptionIcon } from '../svg/subscription'; +import { ticketIcon } from '../svg/ticket'; +import { ticketReservedIcon } from '../svg/ticket-reserved'; +import { visibilityOnIcon } from '../svg/visibility-on'; +import { visibilityoffIcon } from '../svg/visibilityoff'; +import { waitingListIcon } from '../svg/waiting-list'; +import { warningIcon } from '../svg/warning'; + +const ICONS = [ + accessIcon, + accountcircleIcon, + addCircleNewIcon, + addIcon, + arrowBackIcon, + arrowdropdownIcon, + calendarEventIcon, + categoryIcon, + checkIcon, + deleteIcon, + descriptionIcon, + detailsIcon, + downloadIcon, + editIcon, + emailSentIcon, + eventIcon, + groupsIcon, + homeIcon, + hourglassTopIcon, + insightsIcon, + keyIcon, + lockIcon, + lockOpenIcon, + organizationIcon, + paymentsIcon, + percentIcon, + piggyBankIcon, + resetIcon, + searchIcon, + settingsIcon, + subscriptionIcon, + ticketIcon, + ticketReservedIcon, + visibilityoffIcon, + visibilityOnIcon, + waitingListIcon, + lockIcon, + outgoingMailIcon, + qrCodeIcon, + warningIcon, + closeIcon, + infoIcon, +]; +export const ICON_CONFIG = { + sizes: { + xs: '10px', + sm: '12px', + md: '16px', + lg: '20px', + xl: '25px', + xxl: '30px', + }, + defaultSize: 'xl', + icons: ICONS, +}; diff --git a/frontend/projects/admin/src/app/shared/organization.service.ts b/frontend/projects/admin/src/app/shared/organization.service.ts new file mode 100644 index 0000000000..4055932746 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/organization.service.ts @@ -0,0 +1,28 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { Organization } from '../model/organization'; + +@Injectable() +export class OrganizationService { + constructor(private httpClient: HttpClient) {} + + getOrganizations(): Observable { + return this.httpClient.get('/admin/api/organizations'); + } + + getOrganization(id: number | string): Observable { + return this.httpClient.get(`/admin/api/organizations/${id}`); + } + + create(organization: Organization): Observable { + return this.httpClient.post( + '/admin/api/organizations/new', + organization + ); + } + + update(organization : Organization) : Observable { + return this.httpClient.post('/admin/api/organizations/update', organization); + } +} diff --git a/frontend/projects/admin/src/app/shared/section-dashboard/section-dashboard.component.html b/frontend/projects/admin/src/app/shared/section-dashboard/section-dashboard.component.html new file mode 100644 index 0000000000..d649b435da --- /dev/null +++ b/frontend/projects/admin/src/app/shared/section-dashboard/section-dashboard.component.html @@ -0,0 +1,12 @@ +
+
+ +
+
+
+ +
+
+
diff --git a/frontend/projects/admin/src/app/shared/section-dashboard/section-dashboard.component.ts b/frontend/projects/admin/src/app/shared/section-dashboard/section-dashboard.component.ts new file mode 100644 index 0000000000..e1161d8dd9 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/section-dashboard/section-dashboard.component.ts @@ -0,0 +1,15 @@ +import {Component, Input} from "@angular/core"; + +@Component({ + selector: 'app-section-dashboard', + templateUrl: './section-dashboard.component.html' +}) +export class SectionDashboardComponent { + + @Input() + hasMenu = false; + +} + + + diff --git a/frontend/projects/admin/src/app/shared/shared.module.ts b/frontend/projects/admin/src/app/shared/shared.module.ts new file mode 100644 index 0000000000..49cf86aae1 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/shared.module.ts @@ -0,0 +1,22 @@ +import {NgModule} from "@angular/core"; +import {SectionDashboardComponent} from "./section-dashboard/section-dashboard.component"; +import {UserNamePipe} from "./user-name.pipe"; +import {NgIf} from "@angular/common"; +import { UsersFilterOrgPipe } from "./users-filter-org.pipe"; + +@NgModule({ + declarations: [ + SectionDashboardComponent, + UserNamePipe, + UsersFilterOrgPipe, + ], + imports: [ + NgIf + ], + exports: [ + SectionDashboardComponent, + UserNamePipe, + UsersFilterOrgPipe, + ] +}) +export class SharedModule {} diff --git a/frontend/projects/admin/src/app/shared/user-name.pipe.ts b/frontend/projects/admin/src/app/shared/user-name.pipe.ts new file mode 100644 index 0000000000..6a2ca84765 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/user-name.pipe.ts @@ -0,0 +1,16 @@ +import {Pipe, PipeTransform} from "@angular/core"; +import {UserInfo} from "../model/user"; + +@Pipe({ + name: 'userName', + pure: true +}) +export class UserNamePipe implements PipeTransform { + transform(user: UserInfo | null): string { + if (user != null) { + return user.firstName + " " + user.lastName; + } + return ""; + } + +} diff --git a/frontend/projects/admin/src/app/shared/user.service.ts b/frontend/projects/admin/src/app/shared/user.service.ts new file mode 100644 index 0000000000..853f06fb7b --- /dev/null +++ b/frontend/projects/admin/src/app/shared/user.service.ts @@ -0,0 +1,80 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { catchError, filter, map, Observable, of } from 'rxjs'; +import { User, UserInfo} from '../model/user'; +import { Role } from '../model/role'; +import { ApiKeyBulk } from '../model/apikey-bulk'; + +@Injectable() +export class UserService { + constructor(private httpClient: HttpClient) {} + + public checkUserLoggedIn(): Observable { + return this.httpClient + .get<{ authenticated: boolean }>('/authentication-status', { + observe: 'response', + }) + .pipe( + map((resp) => { + return resp.status === 200 && (resp.body?.authenticated || false); + }), + catchError((err) => { + console.log('error!', err); + return of(false); + }) + ); + } + + getCurrent(): Observable { + return this.httpClient.get('/admin/api/users/current'); + } + + getAllUsers(): Observable { + return this.getAll().pipe( + map((users) => users.filter((user) => user.type !== 'API_KEY')) + ); + } + + getAllApiKey(): Observable { + return this.getAll().pipe( + map((users) => users.filter((user) => user.type === 'API_KEY')) + ); + } + + getAll(): Observable { + return this.httpClient.get('/admin/api/users'); + } + + enable(user: User, enabled: boolean): Observable { + return this.httpClient.post( + `/admin/api/users/${user.id}/enable/${enabled}`, + {} + ); + } + + deleteUser(user: User): Observable { + return this.httpClient.delete(`/admin/api/users/${user.id}`); + } + + getAllRoles(): Observable { + return this.httpClient.get('/admin/api/roles'); + } + + create(user: User): Observable { + return this.httpClient.post('/admin/api/users/new', user, { + params: { baseUrl: window.location.origin }, + }); + } + + getUser(id: number | string) : Observable{ + return this.httpClient.get(`/admin/api/users/${id}`); + } + + update(user: User) : Observable{ + return this.httpClient.post('/admin/api/users/edit', user); + } + + createApiBulk(apiKeyBulk: ApiKeyBulk): Observable{ + return this.httpClient.post('/admin/api/api-keys/bulk', apiKeyBulk); + } +} diff --git a/frontend/projects/admin/src/app/shared/users-filter-org.pipe.ts b/frontend/projects/admin/src/app/shared/users-filter-org.pipe.ts new file mode 100644 index 0000000000..ea2789bb49 --- /dev/null +++ b/frontend/projects/admin/src/app/shared/users-filter-org.pipe.ts @@ -0,0 +1,26 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { User } from '../model/user'; +import { Organization } from '../model/organization'; + +@Pipe({ + name: 'usersFilterOrg', + pure: true, +}) +export class UsersFilterOrgPipe implements PipeTransform { + transform( + value: User[] | null, + org: Organization | undefined + ): User[] | null { + if (!value) { + return value; + } + return value.filter((user) => { + if (!org) { + return true; + } + return user.memberOf.some( + (userOrganization) => userOrganization.id === org.id + ); + }); + } +} diff --git a/frontend/projects/admin/src/app/svg/access.ts b/frontend/projects/admin/src/app/svg/access.ts new file mode 100644 index 0000000000..f37971a8e6 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/access.ts @@ -0,0 +1,4 @@ +export const accessIcon = { + data: ``, + name: 'access' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/accountcircle.ts b/frontend/projects/admin/src/app/svg/accountcircle.ts new file mode 100644 index 0000000000..99f45a0c04 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/accountcircle.ts @@ -0,0 +1,4 @@ +export const accountcircleIcon = { + data: ``, + name: 'accountcircle' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/add-circle-new.ts b/frontend/projects/admin/src/app/svg/add-circle-new.ts new file mode 100644 index 0000000000..8a405ac1c1 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/add-circle-new.ts @@ -0,0 +1,4 @@ +export const addCircleNewIcon = { + data: ``, + name: 'add-circle-new' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/add.ts b/frontend/projects/admin/src/app/svg/add.ts new file mode 100644 index 0000000000..da716c2bc8 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/add.ts @@ -0,0 +1,4 @@ +export const addIcon = { + data: ``, + name: 'add' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/arrow-back.ts b/frontend/projects/admin/src/app/svg/arrow-back.ts new file mode 100644 index 0000000000..ab150e0245 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/arrow-back.ts @@ -0,0 +1,4 @@ +export const arrowBackIcon = { + data: ``, + name: 'arrow-back' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/arrowdropdown.ts b/frontend/projects/admin/src/app/svg/arrowdropdown.ts new file mode 100644 index 0000000000..2dae240495 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/arrowdropdown.ts @@ -0,0 +1,4 @@ +export const arrowdropdownIcon = { + data: ``, + name: 'arrowdropdown' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/calendar-event.ts b/frontend/projects/admin/src/app/svg/calendar-event.ts new file mode 100644 index 0000000000..d33091e601 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/calendar-event.ts @@ -0,0 +1,4 @@ +export const calendarEventIcon = { + data: ``, + name: 'calendar-event' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/category.ts b/frontend/projects/admin/src/app/svg/category.ts new file mode 100644 index 0000000000..d0be84781e --- /dev/null +++ b/frontend/projects/admin/src/app/svg/category.ts @@ -0,0 +1,4 @@ +export const categoryIcon = { + data: ``, + name: 'category' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/check.ts b/frontend/projects/admin/src/app/svg/check.ts new file mode 100644 index 0000000000..2efa6b4b4b --- /dev/null +++ b/frontend/projects/admin/src/app/svg/check.ts @@ -0,0 +1,4 @@ +export const checkIcon = { + data: ``, + name: 'check' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/close.ts b/frontend/projects/admin/src/app/svg/close.ts new file mode 100644 index 0000000000..64683a5a67 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/close.ts @@ -0,0 +1,4 @@ +export const closeIcon = { + data: ``, + name: 'close' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/delete.ts b/frontend/projects/admin/src/app/svg/delete.ts new file mode 100644 index 0000000000..773b1d033d --- /dev/null +++ b/frontend/projects/admin/src/app/svg/delete.ts @@ -0,0 +1,4 @@ +export const deleteIcon = { + data: ``, + name: 'delete' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/description.ts b/frontend/projects/admin/src/app/svg/description.ts new file mode 100644 index 0000000000..f2e4423d29 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/description.ts @@ -0,0 +1,4 @@ +export const descriptionIcon = { + data: ``, + name: 'description' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/details.ts b/frontend/projects/admin/src/app/svg/details.ts new file mode 100644 index 0000000000..df49ed70ef --- /dev/null +++ b/frontend/projects/admin/src/app/svg/details.ts @@ -0,0 +1,4 @@ +export const detailsIcon = { + data: ``, + name: 'details' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/download.ts b/frontend/projects/admin/src/app/svg/download.ts new file mode 100644 index 0000000000..934ea6c6a6 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/download.ts @@ -0,0 +1,4 @@ +export const downloadIcon = { + data: ``, + name: 'download' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/edit.ts b/frontend/projects/admin/src/app/svg/edit.ts new file mode 100644 index 0000000000..6374ac0a39 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/edit.ts @@ -0,0 +1,4 @@ +export const editIcon = { + data: ``, + name: 'edit' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/email-sent.ts b/frontend/projects/admin/src/app/svg/email-sent.ts new file mode 100644 index 0000000000..81353de4f3 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/email-sent.ts @@ -0,0 +1,4 @@ +export const emailSentIcon = { + data: ``, + name: 'email-sent' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/event.ts b/frontend/projects/admin/src/app/svg/event.ts new file mode 100644 index 0000000000..214e5ac0d0 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/event.ts @@ -0,0 +1,4 @@ +export const eventIcon = { + data: ``, + name: 'event' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/groups.ts b/frontend/projects/admin/src/app/svg/groups.ts new file mode 100644 index 0000000000..c3c23de539 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/groups.ts @@ -0,0 +1,4 @@ +export const groupsIcon = { + data: ``, + name: 'groups' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/home.ts b/frontend/projects/admin/src/app/svg/home.ts new file mode 100644 index 0000000000..c9b93d6f01 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/home.ts @@ -0,0 +1,4 @@ +export const homeIcon = { + data: ``, + name: 'home' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/hourglass-top.ts b/frontend/projects/admin/src/app/svg/hourglass-top.ts new file mode 100644 index 0000000000..5ce9c79df4 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/hourglass-top.ts @@ -0,0 +1,4 @@ +export const hourglassTopIcon = { + data: ``, + name: 'hourglass-top' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/info.ts b/frontend/projects/admin/src/app/svg/info.ts new file mode 100644 index 0000000000..a6ed8645d5 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/info.ts @@ -0,0 +1,4 @@ +export const infoIcon = { + data: ``, + name: 'info' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/insights.ts b/frontend/projects/admin/src/app/svg/insights.ts new file mode 100644 index 0000000000..02bc9ba3c9 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/insights.ts @@ -0,0 +1,4 @@ +export const insightsIcon = { + data: ``, + name: 'insights' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/key.ts b/frontend/projects/admin/src/app/svg/key.ts new file mode 100644 index 0000000000..21b3337ae0 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/key.ts @@ -0,0 +1,4 @@ +export const keyIcon = { + data: ``, + name: 'key' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/lock-open.ts b/frontend/projects/admin/src/app/svg/lock-open.ts new file mode 100644 index 0000000000..07ca2a1ba0 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/lock-open.ts @@ -0,0 +1,4 @@ +export const lockOpenIcon = { + data: ``, + name: 'lock-open' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/lock.ts b/frontend/projects/admin/src/app/svg/lock.ts new file mode 100644 index 0000000000..9359492e22 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/lock.ts @@ -0,0 +1,4 @@ +export const lockIcon = { + data: ``, + name: 'lock' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/organization.ts b/frontend/projects/admin/src/app/svg/organization.ts new file mode 100644 index 0000000000..1d137cacce --- /dev/null +++ b/frontend/projects/admin/src/app/svg/organization.ts @@ -0,0 +1,4 @@ +export const organizationIcon = { + data: ``, + name: 'organization' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/outgoing-mail.ts b/frontend/projects/admin/src/app/svg/outgoing-mail.ts new file mode 100644 index 0000000000..58d930fca3 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/outgoing-mail.ts @@ -0,0 +1,4 @@ +export const outgoingMailIcon = { + data: ``, + name: 'outgoing-mail' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/payments.ts b/frontend/projects/admin/src/app/svg/payments.ts new file mode 100644 index 0000000000..a3efc9f14f --- /dev/null +++ b/frontend/projects/admin/src/app/svg/payments.ts @@ -0,0 +1,4 @@ +export const paymentsIcon = { + data: ``, + name: 'payments' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/percent.ts b/frontend/projects/admin/src/app/svg/percent.ts new file mode 100644 index 0000000000..05f6fb1a41 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/percent.ts @@ -0,0 +1,4 @@ +export const percentIcon = { + data: ``, + name: 'percent' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/piggy-bank.ts b/frontend/projects/admin/src/app/svg/piggy-bank.ts new file mode 100644 index 0000000000..cd15d15ef1 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/piggy-bank.ts @@ -0,0 +1,4 @@ +export const piggyBankIcon = { + data: ``, + name: 'piggy-bank' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/qr-code.ts b/frontend/projects/admin/src/app/svg/qr-code.ts new file mode 100644 index 0000000000..31ef01a211 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/qr-code.ts @@ -0,0 +1,4 @@ +export const qrCodeIcon = { + data: ``, + name: 'qr-code' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/reset.ts b/frontend/projects/admin/src/app/svg/reset.ts new file mode 100644 index 0000000000..5a77218e49 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/reset.ts @@ -0,0 +1,4 @@ +export const resetIcon = { + data: ``, + name: 'reset' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/search.ts b/frontend/projects/admin/src/app/svg/search.ts new file mode 100644 index 0000000000..4c625f88bd --- /dev/null +++ b/frontend/projects/admin/src/app/svg/search.ts @@ -0,0 +1,4 @@ +export const searchIcon = { + data: ``, + name: 'search' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/settings.ts b/frontend/projects/admin/src/app/svg/settings.ts new file mode 100644 index 0000000000..aa6c7b9c04 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/settings.ts @@ -0,0 +1,4 @@ +export const settingsIcon = { + data: ``, + name: 'settings' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/subscription.ts b/frontend/projects/admin/src/app/svg/subscription.ts new file mode 100644 index 0000000000..1ddf448bfc --- /dev/null +++ b/frontend/projects/admin/src/app/svg/subscription.ts @@ -0,0 +1,4 @@ +export const subscriptionIcon = { + data: ``, + name: 'subscription' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/ticket-reserved.ts b/frontend/projects/admin/src/app/svg/ticket-reserved.ts new file mode 100644 index 0000000000..1bf2e5876f --- /dev/null +++ b/frontend/projects/admin/src/app/svg/ticket-reserved.ts @@ -0,0 +1,4 @@ +export const ticketReservedIcon = { + data: ``, + name: 'ticket-reserved' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/ticket.ts b/frontend/projects/admin/src/app/svg/ticket.ts new file mode 100644 index 0000000000..c53182ab43 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/ticket.ts @@ -0,0 +1,4 @@ +export const ticketIcon = { + data: ``, + name: 'ticket' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/visibility-on.ts b/frontend/projects/admin/src/app/svg/visibility-on.ts new file mode 100644 index 0000000000..c044e4bc7b --- /dev/null +++ b/frontend/projects/admin/src/app/svg/visibility-on.ts @@ -0,0 +1,4 @@ +export const visibilityOnIcon = { + data: ``, + name: 'visibility-on' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/visibilityoff.ts b/frontend/projects/admin/src/app/svg/visibilityoff.ts new file mode 100644 index 0000000000..e7ed5863a7 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/visibilityoff.ts @@ -0,0 +1,4 @@ +export const visibilityoffIcon = { + data: ``, + name: 'visibilityoff' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/waiting-list.ts b/frontend/projects/admin/src/app/svg/waiting-list.ts new file mode 100644 index 0000000000..bdc6d7b78e --- /dev/null +++ b/frontend/projects/admin/src/app/svg/waiting-list.ts @@ -0,0 +1,4 @@ +export const waitingListIcon = { + data: ``, + name: 'waiting-list' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/svg/warning.ts b/frontend/projects/admin/src/app/svg/warning.ts new file mode 100644 index 0000000000..a978066122 --- /dev/null +++ b/frontend/projects/admin/src/app/svg/warning.ts @@ -0,0 +1,4 @@ +export const warningIcon = { + data: ``, + name: 'warning' as const +}; \ No newline at end of file diff --git a/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.html b/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.html new file mode 100644 index 0000000000..4457c39728 --- /dev/null +++ b/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.html @@ -0,0 +1,96 @@ +
+

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
diff --git a/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.scss b/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.ts b/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.ts new file mode 100644 index 0000000000..377af17ac2 --- /dev/null +++ b/frontend/projects/admin/src/app/user-system-edit/user-system-edit.component.ts @@ -0,0 +1,92 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { OrganizationService } from '../shared/organization.service'; +import { UserService } from '../shared/user.service'; +import { Observable, map, of } from 'rxjs'; +import { Organization } from '../model/organization'; +import { Role } from '../model/role'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RoleType, User } from '../model/user'; + +@Component({ + selector: 'app-user-system-edit', + templateUrl: './user-system-edit.component.html', + styleUrls: ['./user-system-edit.component.scss'], +}) +export class UserSystemEditComponent implements OnInit { + public userId: string | null = null; + public userForm: FormGroup; + public organizations$?: Observable; + public roles$?: Observable; + public editMode: boolean | undefined; + public user$: Observable = of(); + constructor( + private readonly route: ActivatedRoute, + formBuilder: FormBuilder, + private readonly organizationService: OrganizationService, + private readonly userService: UserService, + private readonly router: Router + ) { + this.userForm = formBuilder.group({ + target: null, + id: [null], + organizationId: [null, Validators.required], + role: [null, Validators.required], + username: [null, Validators.required], + firstName: [null, Validators.required], + lastName: [null, Validators.required], + emailAddress: [null, Validators.required], + }); + } + + get userName() { + return this.userForm.get('username'); + } + get userLastName() { + return this.userForm.get('lastName'); + } + get userFirstName() { + return this.userForm.get('firstName'); + } + + get userMail() { + return this.userForm.get('emailAddress'); + } + + ngOnInit(): void { + this.userId = this.route.snapshot.paramMap.get('userId'); + + this.organizations$ = this.organizationService.getOrganizations(); + this.roles$ = this.userService.getAllRoles().pipe( + map((roles) => { + return roles.filter((role) => role.target.includes('USER')); + }) + ); + + if (this.userId !== null) { + this.editMode = true; + this.user$ = this.userService.getUser(this.userId); + this.user$.subscribe((user) => { + if (user) this.userForm.patchValue(user); + }); + } else { + this.editMode = false; + } + } + + save(): void { + let result: Observable; + if (this.editMode) { + result = this.userService.update(this.userForm.value); + } else { + result = this.userService.create(this.userForm.value); + } + result.subscribe((res) => { + if (res === 'OK') { + this.router.navigate(['/access-control/users']); + } + }); + } + + +} diff --git a/frontend/projects/admin/src/app/user-system/user-system.component.html b/frontend/projects/admin/src/app/user-system/user-system.component.html new file mode 100644 index 0000000000..cab790a3c1 --- /dev/null +++ b/frontend/projects/admin/src/app/user-system/user-system.component.html @@ -0,0 +1,107 @@ +
+

+
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ / +
{{ user.enabled }} + {{ user.username }} + {{ user.firstName }} {{ user.lastName }} + {{ + roleDescription(role) | async + }} + + {{ + org.name + }} + + + + + + + + + + +
+
diff --git a/frontend/projects/admin/src/app/user-system/user-system.component.scss b/frontend/projects/admin/src/app/user-system/user-system.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/admin/src/app/user-system/user-system.component.ts b/frontend/projects/admin/src/app/user-system/user-system.component.ts new file mode 100644 index 0000000000..9708bcac2d --- /dev/null +++ b/frontend/projects/admin/src/app/user-system/user-system.component.ts @@ -0,0 +1,70 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable, map, of, share, shareReplay } from 'rxjs'; +import { UserService } from '../shared/user.service'; +import { RoleType, User, UserType } from '../model/user'; +import { Role } from '../model/role'; +import { Organization } from '../model/organization'; + +@Component({ + selector: 'app-user-system', + templateUrl: './user-system.component.html', + styleUrls: ['./user-system.component.scss'], +}) +export class UserSystemComponent implements OnInit { + public users$?: Observable; + public roles$: Observable> = of(); + public organizations$?: Observable; + public selectedOrganization?: Organization; + + constructor(private readonly userService: UserService) {} + + ngOnInit(): void { + this.loadUsers(); + this.roles$ = this.userService.getAllRoles().pipe( + map((roles) => { + const map: Map = new Map(); + roles.forEach((role) => { + map.set(role.role, role); + }); + return map; + }), + shareReplay(1) + ); + } + + private loadUsers(){ + this.users$ = this.userService.getAllUsers(); + this.users$.subscribe((users) => { + const orgIdToOrg = new Map(); + users.forEach((user) => { + user.memberOf.forEach((org) => { + orgIdToOrg.set(org.id, org); + }); + }); + + const organizations = Array.from(orgIdToOrg.values()); + this.organizations$ = of(organizations); + }); + + } + + enable(user: User) { + this.userService.enable(user, !user.enabled).subscribe((result) => { + this.users$ = this.userService.getAllUsers(); + }); + } + + deleteUser(user: User) { + if ( + window.confirm(`The user ${user.username} will be deleted. Are you sure?`) + ) { + this.userService.deleteUser(user).subscribe((result) => { + this.users$ = this.userService.getAllUsers(); + }); + } + } + + roleDescription(role: RoleType): Observable { + return this.roles$.pipe(map((roles) => roles.get(role)?.description)); + } +} diff --git a/frontend/projects/admin/src/assets/alfio-logo.svg b/frontend/projects/admin/src/assets/alfio-logo.svg new file mode 100644 index 0000000000..cdd73fd48d --- /dev/null +++ b/frontend/projects/admin/src/assets/alfio-logo.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/frontend/projects/admin/src/assets/svg/access.svg b/frontend/projects/admin/src/assets/svg/access.svg new file mode 100644 index 0000000000..e8a60e358f --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/access.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/accountcircle.svg b/frontend/projects/admin/src/assets/svg/accountcircle.svg new file mode 100644 index 0000000000..9419ad7859 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/accountcircle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/add-circle-new.svg b/frontend/projects/admin/src/assets/svg/add-circle-new.svg new file mode 100644 index 0000000000..0570982608 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/add-circle-new.svg @@ -0,0 +1 @@ + diff --git a/frontend/projects/admin/src/assets/svg/add.svg b/frontend/projects/admin/src/assets/svg/add.svg new file mode 100644 index 0000000000..76d4d8a219 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/arrow-back.svg b/frontend/projects/admin/src/assets/svg/arrow-back.svg new file mode 100644 index 0000000000..5811847c7d --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/arrow-back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/arrowdropdown.svg b/frontend/projects/admin/src/assets/svg/arrowdropdown.svg new file mode 100644 index 0000000000..b1bd72c0c9 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/arrowdropdown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/calendar-event.svg b/frontend/projects/admin/src/assets/svg/calendar-event.svg new file mode 100644 index 0000000000..74cda1d15a --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/calendar-event.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/category.svg b/frontend/projects/admin/src/assets/svg/category.svg new file mode 100644 index 0000000000..b7996a6365 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/category.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/check.svg b/frontend/projects/admin/src/assets/svg/check.svg new file mode 100644 index 0000000000..f3ab4225ee --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/close.svg b/frontend/projects/admin/src/assets/svg/close.svg new file mode 100644 index 0000000000..ded3e2a6e7 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/delete.svg b/frontend/projects/admin/src/assets/svg/delete.svg new file mode 100644 index 0000000000..af36de6ca5 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/description.svg b/frontend/projects/admin/src/assets/svg/description.svg new file mode 100644 index 0000000000..fcdbdfcc32 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/description.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/details.svg b/frontend/projects/admin/src/assets/svg/details.svg new file mode 100644 index 0000000000..f5efea3c66 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/details.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/download.svg b/frontend/projects/admin/src/assets/svg/download.svg new file mode 100644 index 0000000000..f8c4fdc6c5 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/edit.svg b/frontend/projects/admin/src/assets/svg/edit.svg new file mode 100644 index 0000000000..3a6ed16da0 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/email-sent.svg b/frontend/projects/admin/src/assets/svg/email-sent.svg new file mode 100644 index 0000000000..f98549747c --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/email-sent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/event.svg b/frontend/projects/admin/src/assets/svg/event.svg new file mode 100644 index 0000000000..4e91a2949f --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/event.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/groups.svg b/frontend/projects/admin/src/assets/svg/groups.svg new file mode 100644 index 0000000000..9b3c14682d --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/home.svg b/frontend/projects/admin/src/assets/svg/home.svg new file mode 100644 index 0000000000..6a001268a4 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/hourglass-top.svg b/frontend/projects/admin/src/assets/svg/hourglass-top.svg new file mode 100644 index 0000000000..eb4fa09eb7 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/hourglass-top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/info.svg b/frontend/projects/admin/src/assets/svg/info.svg new file mode 100644 index 0000000000..cb0add7937 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/insights.svg b/frontend/projects/admin/src/assets/svg/insights.svg new file mode 100644 index 0000000000..2fc09b2df5 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/insights.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/key.svg b/frontend/projects/admin/src/assets/svg/key.svg new file mode 100644 index 0000000000..2098912039 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/lock-open.svg b/frontend/projects/admin/src/assets/svg/lock-open.svg new file mode 100644 index 0000000000..5316085624 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/lock-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/lock.svg b/frontend/projects/admin/src/assets/svg/lock.svg new file mode 100644 index 0000000000..9ef76e5368 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/organization.svg b/frontend/projects/admin/src/assets/svg/organization.svg new file mode 100644 index 0000000000..e970c3e370 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/organization.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/outgoing-mail.svg b/frontend/projects/admin/src/assets/svg/outgoing-mail.svg new file mode 100644 index 0000000000..1fc98d35a9 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/outgoing-mail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/payments.svg b/frontend/projects/admin/src/assets/svg/payments.svg new file mode 100644 index 0000000000..49cb64615a --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/payments.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/percent.svg b/frontend/projects/admin/src/assets/svg/percent.svg new file mode 100644 index 0000000000..e15c8b523c --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/percent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/piggy-bank.svg b/frontend/projects/admin/src/assets/svg/piggy-bank.svg new file mode 100644 index 0000000000..db27be1d2a --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/piggy-bank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/qr-code.svg b/frontend/projects/admin/src/assets/svg/qr-code.svg new file mode 100644 index 0000000000..6ab295d9df --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/qr-code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/reset.svg b/frontend/projects/admin/src/assets/svg/reset.svg new file mode 100644 index 0000000000..d804df854d --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/reset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/search.svg b/frontend/projects/admin/src/assets/svg/search.svg new file mode 100644 index 0000000000..f51c92487b --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/settings.svg b/frontend/projects/admin/src/assets/svg/settings.svg new file mode 100644 index 0000000000..0d6f5507c4 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/subscription.svg b/frontend/projects/admin/src/assets/svg/subscription.svg new file mode 100644 index 0000000000..89fa2db197 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/subscription.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/ticket-reserved.svg b/frontend/projects/admin/src/assets/svg/ticket-reserved.svg new file mode 100644 index 0000000000..c34fbb89e3 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/ticket-reserved.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/ticket.svg b/frontend/projects/admin/src/assets/svg/ticket.svg new file mode 100644 index 0000000000..01b18f9860 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/ticket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/visibility-on.svg b/frontend/projects/admin/src/assets/svg/visibility-on.svg new file mode 100644 index 0000000000..659d390075 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/visibility-on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/visibilityoff.svg b/frontend/projects/admin/src/assets/svg/visibilityoff.svg new file mode 100644 index 0000000000..90e94063c4 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/visibilityoff.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/waiting-list.svg b/frontend/projects/admin/src/assets/svg/waiting-list.svg new file mode 100644 index 0000000000..3376369847 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/waiting-list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/assets/svg/warning.svg b/frontend/projects/admin/src/assets/svg/warning.svg new file mode 100644 index 0000000000..21f59d38a4 --- /dev/null +++ b/frontend/projects/admin/src/assets/svg/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/projects/admin/src/environments/environment.prod.ts b/frontend/projects/admin/src/environments/environment.prod.ts new file mode 100644 index 0000000000..3612073bc3 --- /dev/null +++ b/frontend/projects/admin/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/frontend/projects/admin/src/environments/environment.ts b/frontend/projects/admin/src/environments/environment.ts new file mode 100644 index 0000000000..f56ff47022 --- /dev/null +++ b/frontend/projects/admin/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/frontend/projects/admin/src/favicon.ico b/frontend/projects/admin/src/favicon.ico new file mode 100644 index 0000000000..997406ad22 Binary files /dev/null and b/frontend/projects/admin/src/favicon.ico differ diff --git a/frontend/projects/admin/src/index.html b/frontend/projects/admin/src/index.html new file mode 100644 index 0000000000..42dae1e082 --- /dev/null +++ b/frontend/projects/admin/src/index.html @@ -0,0 +1,13 @@ + + + + + Alf.io + + + + + + + + diff --git a/frontend/projects/admin/src/main.ts b/frontend/projects/admin/src/main.ts new file mode 100644 index 0000000000..484b5f3d3a --- /dev/null +++ b/frontend/projects/admin/src/main.ts @@ -0,0 +1,12 @@ +import {enableProdMode} from '@angular/core'; +import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; + +import {AppModule} from './app/app.module'; +import {environment} from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/frontend/projects/admin/src/polyfills.ts b/frontend/projects/admin/src/polyfills.ts new file mode 100644 index 0000000000..24785a35a2 --- /dev/null +++ b/frontend/projects/admin/src/polyfills.ts @@ -0,0 +1,54 @@ +/*************************************************************************************************** + * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. + */ +import '@angular/localize/init'; +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes recent versions of Safari, Chrome (including + * Opera), Edge on the desktop, and iOS and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ +/*************************************************************************************************** + * BROWSER POLYFILLS + */ +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/frontend/projects/admin/src/styles.scss b/frontend/projects/admin/src/styles.scss new file mode 100644 index 0000000000..3394866fa0 --- /dev/null +++ b/frontend/projects/admin/src/styles.scss @@ -0,0 +1,13 @@ +/* You can add global styles to this file, and also import other style files */ + +@import "font/font.scss"; + +/* Importing Bootstrap SCSS file. */ +@import "bootstrap/scss/bootstrap"; + +.btn, +.input-group { + svg-icon { + line-height: 0; + } +} diff --git a/frontend/projects/admin/src/test.ts b/frontend/projects/admin/src/test.ts new file mode 100644 index 0000000000..b5adc13140 --- /dev/null +++ b/frontend/projects/admin/src/test.ts @@ -0,0 +1,23 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/testing'; +import {getTestBed} from '@angular/core/testing'; +import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context(path: string, deep?: boolean, filter?: RegExp): { + (id: string): T; + keys(): string[]; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting(), +); + +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().forEach(context); diff --git a/frontend/projects/admin/tsconfig.app.json b/frontend/projects/admin/tsconfig.app.json new file mode 100644 index 0000000000..fd37f74d77 --- /dev/null +++ b/frontend/projects/admin/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/frontend/projects/admin/tsconfig.spec.json b/frontend/projects/admin/tsconfig.spec.json new file mode 100644 index 0000000000..a9c0752ffe --- /dev/null +++ b/frontend/projects/admin/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/frontend/projects/common/README.md b/frontend/projects/common/README.md new file mode 100644 index 0000000000..d932e1b60f --- /dev/null +++ b/frontend/projects/common/README.md @@ -0,0 +1,24 @@ +# Common + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.0. + +## Code scaffolding + +Run `ng generate component component-name --project common` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project common`. +> Note: Don't forget to add `--project common` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build common` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build common`, go to the dist folder `cd dist/common` and run `npm publish`. + +## Running unit tests + +Run `ng test common` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/projects/common/ng-package.json b/frontend/projects/common/ng-package.json new file mode 100644 index 0000000000..1cb4d65793 --- /dev/null +++ b/frontend/projects/common/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/common", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/frontend/projects/common/package-lock.json b/frontend/projects/common/package-lock.json new file mode 100644 index 0000000000..99d920d310 --- /dev/null +++ b/frontend/projects/common/package-lock.json @@ -0,0 +1,117 @@ +{ + "name": "common", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "common", + "version": "0.0.1", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^14.1.1", + "@angular/core": "^14.1.1" + } + }, + "node_modules/@angular/common": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.12.tgz", + "integrity": "sha512-oZunh9wfInFWhNO1P8uoEs/o4u8kerKMhw8GruywKm1TV7gHDP2Fi5WHGjFqq3XYptgBTPCTSEfyLX6Cwq1PUw==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/core": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.12.tgz", + "integrity": "sha512-sGQxU5u4uawwvJa6jOTmGoisJiQ5HIN/RoBw99CmoqZIVyUSg9IRJJC1KVdH8gbpWBNLkElZv21lwJTL/msWyg==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4 || ~0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/zone.js": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.12.0.tgz", + "integrity": "sha512-XtC+I5dXU14HrzidAKBNMqneIVUykLEAA1x+v4KVrd6AUPWlwYORF8KgsVqvgdHiKZ4BkxxjvYi/ksEixTPR0Q==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + } + } + }, + "dependencies": { + "@angular/common": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.12.tgz", + "integrity": "sha512-oZunh9wfInFWhNO1P8uoEs/o4u8kerKMhw8GruywKm1TV7gHDP2Fi5WHGjFqq3XYptgBTPCTSEfyLX6Cwq1PUw==", + "peer": true, + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/core": { + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.12.tgz", + "integrity": "sha512-sGQxU5u4uawwvJa6jOTmGoisJiQ5HIN/RoBw99CmoqZIVyUSg9IRJJC1KVdH8gbpWBNLkElZv21lwJTL/msWyg==", + "peer": true, + "requires": { + "tslib": "^2.3.0" + } + }, + "rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "zone.js": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.12.0.tgz", + "integrity": "sha512-XtC+I5dXU14HrzidAKBNMqneIVUykLEAA1x+v4KVrd6AUPWlwYORF8KgsVqvgdHiKZ4BkxxjvYi/ksEixTPR0Q==", + "peer": true, + "requires": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/frontend/projects/common/package.json b/frontend/projects/common/package.json new file mode 100644 index 0000000000..1a882b8181 --- /dev/null +++ b/frontend/projects/common/package.json @@ -0,0 +1,11 @@ +{ + "name": "common", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^14.1.1", + "@angular/core": "^14.1.1" + }, + "dependencies": { + "tslib": "^2.3.0" + } +} diff --git a/frontend/projects/common/src/lib/alfio-common.module.ts b/frontend/projects/common/src/lib/alfio-common.module.ts new file mode 100644 index 0000000000..7888f4b28b --- /dev/null +++ b/frontend/projects/common/src/lib/alfio-common.module.ts @@ -0,0 +1,13 @@ +import {NgModule} from '@angular/core'; + +@NgModule({ + declarations: [ + ], + imports: [ + ], + providers: [ + ], + exports: [ + ] +}) +export class AlfioCommonModule { } diff --git a/frontend/projects/common/src/lib/xsrf.ts b/frontend/projects/common/src/lib/xsrf.ts new file mode 100644 index 0000000000..957fb52fa5 --- /dev/null +++ b/frontend/projects/common/src/lib/xsrf.ts @@ -0,0 +1,110 @@ +import {Inject, Injectable, Injector, INJECTOR, PLATFORM_ID} from '@angular/core'; +import { + HttpEvent, + HttpHandler, + HttpInterceptor, + HttpRequest, + HttpResponse, + HttpXsrfTokenExtractor +} from '@angular/common/http'; +import {DOCUMENT} from '@angular/common'; +import {Observable} from 'rxjs'; +import {tap} from 'rxjs/operators'; + +const GID_HEADER_NAME = 'x-auth-token'; +const XSRF_TOKEN_HEADER = 'xsrf-token'; + +@Injectable() +export class DOMXsrfTokenExtractor implements HttpXsrfTokenExtractor { + + lastToken: string | null = null; + + constructor(@Inject(DOCUMENT) private doc: Document, + @Inject(PLATFORM_ID) private platform: string) {} + + getToken(): string | null { + if (this.platform === 'server') { + return null; + } + return this.doc.head.querySelector('meta[name="XSRF_TOKEN"]')?.content || null; + } + + updateToken(newVal: string | null): void { + if (newVal == null || newVal === this.lastToken) { + return; + } + const element = retrieveHeadElement('XSRF_TOKEN', this.doc); + element.content = newVal; + this.lastToken = newVal; + } +} + +@Injectable() +export class DOMGidExtractor { + + lastToken: string | null = null; + + constructor(@Inject(DOCUMENT) private doc: Document, + @Inject(PLATFORM_ID) private platform: string) {} + + getToken(): string | null { + if (this.platform === 'server') { + return null; + } + return this.doc.head.querySelector('meta[name="GID"]')?.content || null; + } + + updateToken(newVal: string | null): void { + if (newVal == null || newVal === this.lastToken) { + return; + } + const element = retrieveHeadElement('GID', this.doc); + element.content = newVal; + this.lastToken = newVal; + } +} + +function retrieveHeadElement(name: string, doc: Document): HTMLMetaElement { + let element = doc.head.querySelector(`meta[name="${name}"]`); + if (element == null) { + // it should only happen in dev mode + element = doc.createElement('meta'); + element.name = name; + doc.head.append(element); + } + return element; +} + +@Injectable() +export class AuthTokenInterceptor implements HttpInterceptor { + + private domGidExtractor: DOMGidExtractor | null = null; + private domXsrfTokenExtractor: DOMXsrfTokenExtractor | null = null; + + constructor(@Inject(INJECTOR) private injector: Injector) { + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + this.init(); + return next.handle(req.clone({ + headers: req.headers.set(GID_HEADER_NAME, this.domGidExtractor?.getToken() || '') + })).pipe(tap(response => { + if (response instanceof HttpResponse) { + if (response.headers.has(GID_HEADER_NAME)) { + this.domGidExtractor?.updateToken(response.headers.get(GID_HEADER_NAME)); + } + if (req.method === 'GET' && response.headers.has(XSRF_TOKEN_HEADER)) { + this.domXsrfTokenExtractor?.updateToken(response.headers.get(XSRF_TOKEN_HEADER)); + } + } + })); + } + + private init(): void { + if (this.domGidExtractor == null) { + this.domGidExtractor = this.injector.get(DOMGidExtractor); + this.domXsrfTokenExtractor = this.injector.get(DOMXsrfTokenExtractor); + } + } + +} diff --git a/frontend/projects/common/src/public-api.ts b/frontend/projects/common/src/public-api.ts new file mode 100644 index 0000000000..d6b0386644 --- /dev/null +++ b/frontend/projects/common/src/public-api.ts @@ -0,0 +1,6 @@ +/* + * Public API Surface of common + */ + +export * from './lib/alfio-common.module'; +export * from './lib/xsrf'; diff --git a/frontend/projects/common/style/font/font.scss b/frontend/projects/common/style/font/font.scss new file mode 100644 index 0000000000..84430c82e1 --- /dev/null +++ b/frontend/projects/common/style/font/font.scss @@ -0,0 +1,65 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.cyrillic.woff2') format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.greek-ext.woff2') format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.greek.woff2') format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('/resources/font/SourceSansPro-Regular.latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +$font-family-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; diff --git a/frontend/projects/common/tsconfig.lib.json b/frontend/projects/common/tsconfig.lib.json new file mode 100644 index 0000000000..543fd474ab --- /dev/null +++ b/frontend/projects/common/tsconfig.lib.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/frontend/projects/common/tsconfig.lib.prod.json b/frontend/projects/common/tsconfig.lib.prod.json new file mode 100644 index 0000000000..06de549e10 --- /dev/null +++ b/frontend/projects/common/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/frontend/projects/common/tsconfig.spec.json b/frontend/projects/common/tsconfig.spec.json new file mode 100644 index 0000000000..ce7048bc2c --- /dev/null +++ b/frontend/projects/common/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/frontend/projects/public/README.md b/frontend/projects/public/README.md new file mode 100644 index 0000000000..9ae9e5ecc2 --- /dev/null +++ b/frontend/projects/public/README.md @@ -0,0 +1,29 @@ +[![Build Status](https://travis-ci.org/alfio-event/alf.io-public-frontend.svg?branch=master)](https://travis-ci.org/alfio-event/alf.io-public-frontend) + +# AlfioPublicFrontend + +This is the "public" frontend of [alf.io](https://alf.io/). + +## Development server + +Run `npm run start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/frontend/projects/public/e2e/protractor.conf.js b/frontend/projects/public/e2e/protractor.conf.js new file mode 100644 index 0000000000..86776a391a --- /dev/null +++ b/frontend/projects/public/e2e/protractor.conf.js @@ -0,0 +1,28 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.e2e.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/frontend/projects/public/e2e/src/app.e2e-spec.ts b/frontend/projects/public/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000000..89892fa716 --- /dev/null +++ b/frontend/projects/public/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import {AppPage} from './app.po'; +import {browser, logging} from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('Welcome to alfio-public-frontend!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + })); + }); +}); diff --git a/frontend/projects/public/e2e/src/app.po.ts b/frontend/projects/public/e2e/src/app.po.ts new file mode 100644 index 0000000000..371ad6347d --- /dev/null +++ b/frontend/projects/public/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import {browser, by, element} from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get('/'); + } + + getTitleText() { + return element(by.css('app-root h1')).getText(); + } +} diff --git a/frontend/projects/public/e2e/tsconfig.e2e.json b/frontend/projects/public/e2e/tsconfig.e2e.json new file mode 100644 index 0000000000..a6dd622028 --- /dev/null +++ b/frontend/projects/public/e2e/tsconfig.e2e.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} \ No newline at end of file diff --git a/frontend/projects/public/package-lock.json b/frontend/projects/public/package-lock.json new file mode 100644 index 0000000000..1400ffec07 --- /dev/null +++ b/frontend/projects/public/package-lock.json @@ -0,0 +1,23443 @@ +{ + "name": "alfio-public-frontend", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "alfio-public-frontend", + "version": "0.0.0", + "dependencies": { + "@angular/animations": "^14.1.1", + "@angular/common": "^14.1.1", + "@angular/compiler": "^14.1.1", + "@angular/core": "^14.1.1", + "@angular/forms": "^14.1.1", + "@angular/localize": "^14.1.1", + "@angular/platform-browser": "^14.1.1", + "@angular/platform-browser-dynamic": "^14.1.1", + "@angular/router": "^14.1.1", + "@fortawesome/angular-fontawesome": "^0.11.1", + "@fortawesome/fontawesome-svg-core": "^1.2.35", + "@fortawesome/free-brands-svg-icons": "^5.15.3", + "@fortawesome/free-regular-svg-icons": "^5.15.3", + "@fortawesome/free-solid-svg-icons": "^5.15.3", + "@ng-bootstrap/ng-bootstrap": "^13.0.0", + "@ng-select/ng-select": "^9.0.2", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "bootstrap": "^5.2.0", + "common": "^0.2.5", + "rxjs": "^6.6.3", + "tslib": "^2.0.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.1.1", + "@angular/cli": "^14.1.1", + "@angular/compiler-cli": "^14.1.1", + "@angular/language-service": "^14.1.1", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", + "jasmine-core": "~3.8.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~6.3.9", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~3.0.2", + "karma-jasmine": "~3.3.0", + "karma-jasmine-html-reporter": "^1.7.0", + "protractor": "~7.0.0", + "ts-node": "~7.0.0", + "tslint": "~6.1.0", + "typescript": "~4.7.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1401.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1401.1.tgz", + "integrity": "sha512-HIFrIwbjfXCOjbGlMpHzG3oQG0nM1opaFSeKi+JjzTIb0jWq2s8sJfn4tGOZEJU8aKtDpNYMcW+N3F0grZdR8w==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.1.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.1.1.tgz", + "integrity": "sha512-SlkWvTP6lrXOr5dOLtI56hSX7WuDznaUFHGfXpuwA+buiUgvigzO68VhKfsKn5I44J0PRpqXKPM7bxOXAOMe8Q==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1401.1", + "@angular-devkit/build-webpack": "0.1401.1", + "@angular-devkit/core": "14.1.1", + "@babel/core": "7.18.6", + "@babel/generator": "7.18.7", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.6", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.6", + "@babel/preset-env": "7.18.6", + "@babel/runtime": "7.18.6", + "@babel/template": "7.18.6", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.1.1", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.1", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild-wasm": "0.14.49", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.0", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.14", + "postcss-import": "14.1.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.7.2", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.53.0", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.58.1", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.73.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.9.3", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.14.49" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "@angular/localize": "^14.0.0", + "@angular/service-worker": "^14.0.0", + "karma": "^6.3.0", + "ng-packagr": "^14.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.6.2 <4.8" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", + "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helpers": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1401.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1401.1.tgz", + "integrity": "sha512-MY3KHLSRC6Ev4I9RLoAObyEoT95SYZSdnZQA+2WWcRXzrtCo48IfA1joojo6SLBd4k5uUisBs9aDK1NU8ugbQQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1401.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.1.tgz", + "integrity": "sha512-i5SiU/9xqKbhi5A2kq7ME5KWNXtVIlSLZ/HslGjsolZ4CO0LiZanywcE/HGL7681RVaWVeeSndmKQtqY3mPuNQ==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.1.1.tgz", + "integrity": "sha512-9ymklxBm6ZxB4dvfsowyHQRx+DE7lQShDDMnwT2mPtH7SwbaLEUz02aL4W5BsuR6U1W+M181pZ4Igb3oq0AEoA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.1.1", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/animations": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.1.1.tgz", + "integrity": "sha512-/fXzJzr8Pr7/xpwErX9PjbIc790RF818WgW7SUNev6pN6UUq3gvjmPjDTdZBZfiAZWY49nBLibPo2FvmyCP7tg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.1.1" + } + }, + "node_modules/@angular/cli": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.1.1.tgz", + "integrity": "sha512-Kzx+aUkAi8wx6m2e34Ekvyj9U46w7A3CHn6Zv+//TeplQitoMAzBOE8OiFVEcGJpi5gQ+NLDu0egfh2D+CC+ug==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1401.1", + "@angular-devkit/core": "14.1.1", + "@angular-devkit/schematics": "14.1.1", + "@schematics/angular": "14.1.1", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.1", + "resolve": "1.22.1", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/common": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.1.1.tgz", + "integrity": "sha512-neFCnrIrGOuj3oOFBTLi4QrdI4fgKQprVLUEyL5LhCQ5R0K/F+gh61ovi7nT4XYnv41p4eqtG81YNMtVXH49pg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.1.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.1.1.tgz", + "integrity": "sha512-OT3cFfbHzLpl2M9qpO74oysXDkkKwlO66i4vlASMGf1/Qh+4UBh3iN6bls/ZbYZsl8bCr9zf0fL7c160e1uMcA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.1.1" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.1.1.tgz", + "integrity": "sha512-ERphqFDdN5u1XCZNV21DS0J9/WFZP/P4L4LQTjpEwbO/lDhzxaRnRnLOR6vGcetEHhRHMa0+OL8rrvNy6GwLmw==", + "dependencies": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/main-ngcc.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.1.1", + "typescript": ">=4.6.2 <4.8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@angular/core": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.1.1.tgz", + "integrity": "sha512-l3ms6/jxIUIeuCkXhz5nhRb94KLQ6wv9+B4lE0aJXcgHTqOmhc/ZIacT51LCjvVcok/vczF3f7w71Ii8b10yKQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4" + } + }, + "node_modules/@angular/forms": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.1.1.tgz", + "integrity": "sha512-s4VuaivJ+s2hLlE8CMHLsAAmJNV/03EgBEJQV7rt1H0ogHs0jB/zlkzVw5K5bynCFkfIeDbwd6RvxzWhwE+ong==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.1.1", + "@angular/core": "14.1.1", + "@angular/platform-browser": "14.1.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/language-service": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.1.1.tgz", + "integrity": "sha512-bpUXsScvqzBodt94hEZdAHRZwHf3qqzadBcpTxJLoeJm69Q6hU1OdT7Id8wQfDESREUfbux12E1yVv7rEoIhJg==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0" + } + }, + "node_modules/@angular/localize": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.1.1.tgz", + "integrity": "sha512-SUGTDJYcJoSJWaFcG12njbfnFreZZRnEr3Rs211wD3VSu4UJXrpP1hx2M/FoaHLZkcgpSSfkg/QHLDLYJLRL9Q==", + "dependencies": { + "@babel/core": "7.18.9", + "glob": "8.0.3", + "yargs": "^17.2.1" + }, + "bin": { + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.1.1", + "@angular/compiler-cli": "14.1.1" + } + }, + "node_modules/@angular/localize/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@angular/localize/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular/localize/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/platform-browser": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.1.1.tgz", + "integrity": "sha512-7yXr2GUiI1sD3kmKcWkHwlpmsRyA3WhwJqvjvMPQK4RD8ZeJ5LTOD6nQ4hz1kP19dfzpBDV/k9wusYDlmWtqcw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/animations": "14.1.1", + "@angular/common": "14.1.1", + "@angular/core": "14.1.1" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.1.1.tgz", + "integrity": "sha512-rD5KIWdxYRO2R0oGW6Ipt5pi+Cufws1704QBXhL52uaSJI6Ms7E7jvuwLG2SCJS0FJ+hdYLcuQZiQH+wUuyARA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.1.1", + "@angular/compiler": "14.1.1", + "@angular/core": "14.1.1", + "@angular/platform-browser": "14.1.1" + } + }, + "node_modules/@angular/router": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.1.1.tgz", + "integrity": "sha512-yWgy4NXp0e4XxOXRwaY6YSlOseXoLCVp7jKeBGAqJXypT+HtWXwpWE12vPC8EvkdPLyrf+EuH3kNbSbLfUNtbw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.1.1", + "@angular/core": "14.1.1", + "@angular/platform-browser": "14.1.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", + "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz", + "integrity": "sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", + "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", + "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz", + "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", + "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==", + "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.18.6", + "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.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", + "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6", + "@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==", + "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-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.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==", + "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-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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-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==", + "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-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@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-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", + "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "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==", + "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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "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-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@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-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==", + "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-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-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-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "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-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-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", + "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz", + "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz", + "integrity": "sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "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-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^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-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz", + "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-identifier": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^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-transform-named-capturing-groups-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", + "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "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-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz", + "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz", + "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "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-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz", + "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.6", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.6", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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.18.6", + "@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-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.6", + "@babel/plugin-transform-classes": "^7.18.6", + "@babel/plugin-transform-computed-properties": "^7.18.6", + "@babel/plugin-transform-destructuring": "^7.18.6", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.6", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.6", + "@babel/plugin-transform-function-name": "^7.18.6", + "@babel/plugin-transform-literals": "^7.18.6", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.6", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.6", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.6", + "@babel/plugin-transform-typeof-symbol": "^7.18.6", + "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.6", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "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" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz", + "integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.11", + "@babel/types": "^7.18.10", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.0.5.tgz", + "integrity": "sha512-Id/9wBT7FkgFzdEpiEWrsVd4ltDxN0rI0QS0SChbeQiSuux3z21SJCRLu6h2cvCEUmaRi+VD0mHFj+GJD4GFnw==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@fortawesome/angular-fontawesome": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.11.1.tgz", + "integrity": "sha512-Ngzm5MVxk76ZhYpPTNOI/mpYNz9bzwfBXC5L9mktLgOONjBuYBPVt+bH8lny8hNtDk0ppZzXsMN6CO7hckdfnw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@angular/core": "^14.0.0", + "@fortawesome/fontawesome-svg-core": "~1.2.27 || ~1.3.0-beta2 || ^6.1.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz", + "integrity": "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz", + "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "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/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/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "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==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@ng-bootstrap/ng-bootstrap": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-13.0.0.tgz", + "integrity": "sha512-aumflJ24VVOQ6kIGmpaWmjqfreRsXOCf/l2nOxPO6Y+d7Pit6aZthyjO7F0bRMutv6n+B/ma18GKvhhBcMepUw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^14.1.0", + "@angular/core": "^14.1.0", + "@angular/forms": "^14.1.0", + "@angular/localize": "^14.1.0", + "@popperjs/core": "^2.10.2", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ng-select/ng-select": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-9.0.2.tgz", + "integrity": "sha512-xdNiz/kgkMWYW1qFtk/337xDk/cmfEbSVtTFxWIM2OnIX1XsQOnTlGiBYces1TsMfqS68HjAvljEkj8QIGN2Lg==", + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 12.20.0", + "npm": ">= 6.0.0" + }, + "peerDependencies": { + "@angular/common": "<15.0.0", + "@angular/core": "<15.0.0", + "@angular/forms": "<15.0.0" + } + }, + "node_modules/@ngtools/webpack": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.1.1.tgz", + "integrity": "sha512-pj8sN6jBIi2otTHE/CNQyy09Pmn8tGsZyFrSiNO147yjLnrOSJTeFuXfE2pYgrmcYgj0ybnK1zstt4bAKaL7/Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "typescript": ">=4.6.2 <4.8", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=13.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ngx-translate/http-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-7.0.0.tgz", + "integrity": "sha512-j+NpXXlcGVdyUNyY/qsJrqqeAdJdizCd+GKh3usXExSqy1aE9866jlAIL+xrfDU4w+LiMoma5pgE4emvFebZmA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@ngx-translate/core": ">=14.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "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/@npmcli/fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.1.tgz", + "integrity": "sha512-1Q0uzx6c/NVNGszePbr5Gc2riSU1zLpNlo/1YWntH+eaPmMgBssAW0qXofCVkpdj3ce4swZtlDYQu+NKiYcptg==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.1.tgz", + "integrity": "sha512-UU85F/T+F1oVn3IsB/L6k9zXIMpXBuUBE25QDH0SsURwT6IOBqkC7M16uqo2vVZIyji3X1K4XH9luip7YekH1A==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/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/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.0.tgz", + "integrity": "sha512-UR6D5f4KEGWJV6BGPH3Qb2EtgH+t+1XQ1Tt85c7qicN6cezzuHPdZwwAxqZr4JLtnQu0LZsTza/5gmNmSl8XLg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.0.tgz", + "integrity": "sha512-e/QgLg7j2wSJp1/7JRl0GC8c7PMX+uYlA/1Tb+IDOLdSM4T7K1VQ9mm9IGU3WRtY5vEIObpqCLb3aCNCug18DA==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script/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/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@schematics/angular": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.1.1.tgz", + "integrity": "sha512-oSRDDhzg/27RKrQRoz09yELyBtsAFYfR1f+uq41FcmHZFfwOA5mQaqN2CQ1gUFygUZfZgOWSc+wma3ACIrwbHA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.1.1", + "@angular-devkit/schematics": "14.1.1", + "jsonc-parser": "3.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz", + "integrity": "sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "2.8.18", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.18.tgz", + "integrity": "sha512-CYOO2DsfoFnmYQ+tZyXsExePUomwvUhpSLEsM7kAJ5BSYNlom+5m3qZkxYrg2CoSfJ3tMv5NH02cB0y7GfjvaA==", + "dev": true + }, + "node_modules/@types/jasminewd2": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", + "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", + "dev": true, + "dependencies": { + "@types/jasmine": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "12.20.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz", + "integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.19", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz", + "integrity": "sha512-OFUilxQg+rWL2FMxtmIgCkUDlJB6pskkpvmew7yeXfzzsOBb5rc+y2+DjHm+r3r1ZPPcJefK3DveNSYWGiy68g==", + "dev": true + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.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/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "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/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "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-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "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==", + "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==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.8.tgz", + "integrity": "sha512-75Jr6Q/XpTqEf6D2ltS5uMewJIx5irCU1oBYJrWjFenq/m12WRRrz6g15L1EIoYvPLXTbEry7rDOwrcYNj77xw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.3", + "caniuse-lite": "^1.0.30001373", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "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-polyfill-corejs2": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz", + "integrity": "sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.2", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.13.tgz", + "integrity": "sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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 + }, + "node_modules/bootstrap": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.1.tgz", + "integrity": "sha512-UQi3v2NpVPEi1n35dmRRzBJFlgvWHYwyem6yHhuT6afYF+sziEt46McRbT//kVXZ7b1YUYEVGdXEH74Nx3xzGA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.6" + } + }, + "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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserstack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + } + }, + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browserstack/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.1.tgz", + "integrity": "sha512-VDKN+LHyCQXaaYZ7rA/qtkURU+/yYhviUdvqEv2LT6QPZU8jpyzEkEVAcKlKLt5dJ5BRp11ym8lo3NKLluEPLg==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "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/caniuse-lite": { + "version": "1.0.30001374", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz", + "integrity": "sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "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==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "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==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/common": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/common/-/common-0.2.5.tgz", + "integrity": "sha512-bjuztiY8Wcz2V9dPpa0XdF0unGWqAGsnyKDGV7g6xDcaZfpufRrxV35qhuhjwv1h0jEPeiCHWKAQFLj702jGnA==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js-compat": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.1.tgz", + "integrity": "sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.3", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "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/critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/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/critters/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/critters/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/critters/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/critters/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/critters/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/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/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/css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "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, + "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-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, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css/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/cssdb": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-6.6.3.tgz", + "integrity": "sha512-7GDvDSmE+20+WcSMhP17Q1EVWUrLlbxxpMDqG731n8P99JhnQZHR9YvtjPvEHfjFUjvQJvdpKCjlKOX+xe4UVA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + }, + "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/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "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/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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, + "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" + } + ] + }, + "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, + "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, + "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/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.211", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz", + "integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==" + }, + "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==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "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-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/esbuild": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", + "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.49", + "esbuild-android-arm64": "0.14.49", + "esbuild-darwin-64": "0.14.49", + "esbuild-darwin-arm64": "0.14.49", + "esbuild-freebsd-64": "0.14.49", + "esbuild-freebsd-arm64": "0.14.49", + "esbuild-linux-32": "0.14.49", + "esbuild-linux-64": "0.14.49", + "esbuild-linux-arm": "0.14.49", + "esbuild-linux-arm64": "0.14.49", + "esbuild-linux-mips64le": "0.14.49", + "esbuild-linux-ppc64le": "0.14.49", + "esbuild-linux-riscv64": "0.14.49", + "esbuild-linux-s390x": "0.14.49", + "esbuild-netbsd-64": "0.14.49", + "esbuild-openbsd-64": "0.14.49", + "esbuild-sunos-64": "0.14.49", + "esbuild-windows-32": "0.14.49", + "esbuild-windows-64": "0.14.49", + "esbuild-windows-arm64": "0.14.49" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", + "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", + "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", + "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", + "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", + "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", + "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", + "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", + "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", + "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", + "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", + "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", + "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", + "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", + "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", + "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", + "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", + "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.49.tgz", + "integrity": "sha512-5ddzZv8M3WI1fWZ5rEfK5cSA9swlWJcceKgqjKLLERC7FnlNW50kF7hxhpkyC0Z/4w7Xeyt3yUJ9QWNMDXLk2Q==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", + "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", + "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", + "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "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/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/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/esrecurse/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/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/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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "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": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "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.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "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/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "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/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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==", + "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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "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-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/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "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==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "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/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/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/har-validator/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/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": 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": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "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-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.0.0.tgz", + "integrity": "sha512-rRnjWu0Bxj+nIfUOkz0695C0H6tRrN5iYIzYejb0tDEefe2AekHu/U5Kn9pEie5vsJqpNQU02az7TGSH3qpz4Q==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "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/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "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/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "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/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "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/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/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/node_modules/rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/inquirer/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/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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-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==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "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==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", + "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "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-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/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-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-lib-source-maps/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/istanbul-lib-source-maps/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-reports": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", + "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "dependencies": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.8.0.tgz", + "integrity": "sha512-zl0nZWDrmbCiKns0NcjkFGYkVTGCPUgoHypTaj+G2AzaWus7QGoXARSlYsSle2VRpSdfJmM+hzmFKzQNhF2kHg==", + "dev": true + }, + "node_modules/jasmine-spec-reporter": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz", + "integrity": "sha512-6gP1LbVgJ+d7PKksQBc2H0oDGNRQI3gKUsWlswKaQ2fif9X5gzhQcgM5+kiJGCQVurOG09jqNhk7payggyp5+g==", + "dev": true, + "dependencies": { + "colors": "1.4.0" + } + }, + "node_modules/jasmine/node_modules/jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + }, + "node_modules/jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true, + "engines": { + "node": ">= 6.9.x" + } + }, + "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-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": "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/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "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": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "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/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jszip": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", + "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/karma": { + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", + "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage-istanbul-reporter": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", + "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^3.0.2", + "minimatch": "^3.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/mattlewis92" + } + }, + "node_modules/karma-jasmine": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.3.1.tgz", + "integrity": "sha512-Nxh7eX9mOQMyK0VSsMxdod+bcqrR/ikrmEiWj5M6fwuQ7oI+YEF1FckaDsWfs6TIpULm9f0fTKMjF7XcrvWyqQ==", + "dev": true, + "dependencies": { + "jasmine-core": "^3.5.0" + }, + "engines": { + "node": ">= 8" + }, + "peerDependencies": { + "karma": "*" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": ">=3.8", + "karma": ">=0.9", + "karma-jasmine": ">=1.1" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/karma/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/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/karma/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/karma/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/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/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/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, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "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/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "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==", + "dev": true + }, + "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/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/log4js": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + }, + "engines": { + "node": ">=8.0" + } + }, + "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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.0.tgz", + "integrity": "sha512-OnEfCLofQVJ5zgKwGk55GaqosqKjaR6khQlJY3dBAA+hM25Bc5CmX5rKUfVut+rYA3uidA7zb7AvcglU87rPRg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": 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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "dependencies": { + "mime-db": "1.51.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/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz", + "integrity": "sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", + "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "dev": true, + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.1.0.tgz", + "integrity": "sha512-HkmN0ZpQJU7FLbJauJTHkHlSVAXlNGDAzH/VYFZGDOnFyn/Na3GlNJfkudmufOdS6/jNFhy88ObzL7ERz9es1g==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/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/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-package-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.0.tgz", + "integrity": "sha512-m+GL22VXJKkKbw62ZaBBjv8u6IE3UI4Mh5QakIqs3fWiKe0Xyi6L97hakwZK41/LD4R/2ly71Bayx0NLMwLA/g==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "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==", + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz", + "integrity": "sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^1.1.2", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-packlist/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-packlist/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.0.tgz", + "integrity": "sha512-10LJQ/1+VhKrZjIuY9I/+gQTvumqqlgnsCufoXETHAPFTS3+M+Z5CFhZRDHGavmJ6rOye3UvNga88vl8n1r6gg==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "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.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "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/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/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/ora/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/ora/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/ora/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/ora/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/ora/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/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.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-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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/pacote": { + "version": "13.6.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz", + "integrity": "sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw==", + "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "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/parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "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-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "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/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "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.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.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, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.8", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.8.tgz", + "integrity": "sha512-8rbj8kVu00RQh2fQF81oBqtduiANu4MIxhyf0HbbStgPtnFlWn0yiaYTpLHrPnJbffVY1s9apWsIoVZcc68FxA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.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, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "10.1.10", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.10.tgz", + "integrity": "sha512-lqd7LXCq0gWc0wKXtoKDru5wEUNjm3OryLVNRZ8OnW8km6fSNUuFrjEhU3nklxXE2jvd4qrox566acgh+xQt8w==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", + "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "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, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.7.2.tgz", + "integrity": "sha512-1q0ih7EDsZmCb/FMDRvosna7Gsbdx8CvYO5hYT120hcp2ZAuOHpSzibujZ4JpIUcAC02PG6b+eftxqjTFh5BNA==", + "dev": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.0.4", + "@csstools/postcss-color-function": "^1.1.0", + "@csstools/postcss-font-format-keywords": "^1.0.0", + "@csstools/postcss-hwb-function": "^1.0.1", + "@csstools/postcss-ic-unit": "^1.0.0", + "@csstools/postcss-is-pseudo-class": "^2.0.6", + "@csstools/postcss-normalize-display-values": "^1.0.0", + "@csstools/postcss-oklab-function": "^1.1.0", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.1", + "@csstools/postcss-unset-value": "^1.0.1", + "autoprefixer": "^10.4.7", + "browserslist": "^4.21.0", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^6.6.3", + "postcss-attribute-case-insensitive": "^5.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.3", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.0", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.4", + "postcss-double-position-gradients": "^3.1.1", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.3", + "postcss-image-set-function": "^4.0.6", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.0", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.9", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.3", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.4", + "postcss-pseudo-class-any-link": "^7.1.5", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "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, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "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/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protractor": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "dev": true, + "dependencies": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=10.13.x" + } + }, + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": 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/protractor/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/protractor/node_modules/cliui/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/protractor/node_modules/cliui/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/protractor/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/protractor/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/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/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/protractor/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/protractor/node_modules/wrap-ansi/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/protractor/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-package-json": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.1.tgz", + "integrity": "sha512-MALHuNgYWdGW3gKzuNMuYtcSSZbGQm94fAp16xt8VsYTLBjUSc55bLMKe6gzpWue0Tfi6CBgwCSdDAqutGDhMg==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "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.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "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/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "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/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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-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-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/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/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "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/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "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.53.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz", + "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==", + "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": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/saucelabs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/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/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/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/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/selenium-webdriver/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/selfsigned": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "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/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "node_modules/socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "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/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.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/source-map-support/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/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "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.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "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/stylus": { + "version": "0.58.1", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.58.1.tgz", + "integrity": "sha512-AYiCHm5ogczdCPMfe9aeQa4NklB2gcf4D/IhzYPddJjTgPc+k4D/EVE0yfQbZD43MHP3lPy+8NZ9fcFxkrgs/w==", + "dev": true, + "dependencies": { + "css": "^3.0.0", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "stylus": ">=0.52.4", + "webpack": "^5.0.0" + } + }, + "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==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz", + "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.7", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "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==", + "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==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslint/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/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/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "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/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "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/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "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/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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/validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager": { + "version": "12.1.8", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.8.tgz", + "integrity": "sha512-qJR36SXG2VwKugPcdwhaqcLQOD7r8P2Xiv9sfNbfZrKBnX243iAkOueX1yAmeNgIKhJ3YAT/F2gq6IiEZzahsg==", + "dev": true, + "dependencies": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": 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/webdriver-manager/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/webdriver-manager/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-manager/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webdriver-manager/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webpack": { + "version": "5.73.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", + "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", + "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/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/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/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/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "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/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "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==", + "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==", + "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==", + "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==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "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": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dependencies": { + "cliui": "^7.0.2", + "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.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/zone.js": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.4.tgz", + "integrity": "sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw==", + "dependencies": { + "tslib": "^2.0.0" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/architect": { + "version": "0.1401.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1401.1.tgz", + "integrity": "sha512-HIFrIwbjfXCOjbGlMpHzG3oQG0nM1opaFSeKi+JjzTIb0jWq2s8sJfn4tGOZEJU8aKtDpNYMcW+N3F0grZdR8w==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.1.1", + "rxjs": "6.6.7" + } + }, + "@angular-devkit/build-angular": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.1.1.tgz", + "integrity": "sha512-SlkWvTP6lrXOr5dOLtI56hSX7WuDznaUFHGfXpuwA+buiUgvigzO68VhKfsKn5I44J0PRpqXKPM7bxOXAOMe8Q==", + "dev": true, + "requires": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1401.1", + "@angular-devkit/build-webpack": "0.1401.1", + "@angular-devkit/core": "14.1.1", + "@babel/core": "7.18.6", + "@babel/generator": "7.18.7", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.6", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.6", + "@babel/preset-env": "7.18.6", + "@babel/runtime": "7.18.6", + "@babel/template": "7.18.6", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.1.1", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.1", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild": "0.14.49", + "esbuild-wasm": "0.14.49", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.0", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.14", + "postcss-import": "14.1.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.7.2", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.53.0", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.58.1", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.73.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.9.3", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", + "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helpers": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.1401.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1401.1.tgz", + "integrity": "sha512-MY3KHLSRC6Ev4I9RLoAObyEoT95SYZSdnZQA+2WWcRXzrtCo48IfA1joojo6SLBd4k5uUisBs9aDK1NU8ugbQQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1401.1", + "rxjs": "6.6.7" + } + }, + "@angular-devkit/core": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.1.tgz", + "integrity": "sha512-i5SiU/9xqKbhi5A2kq7ME5KWNXtVIlSLZ/HslGjsolZ4CO0LiZanywcE/HGL7681RVaWVeeSndmKQtqY3mPuNQ==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + } + }, + "@angular-devkit/schematics": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.1.1.tgz", + "integrity": "sha512-9ymklxBm6ZxB4dvfsowyHQRx+DE7lQShDDMnwT2mPtH7SwbaLEUz02aL4W5BsuR6U1W+M181pZ4Igb3oq0AEoA==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.1.1", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + } + }, + "@angular/animations": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.1.1.tgz", + "integrity": "sha512-/fXzJzr8Pr7/xpwErX9PjbIc790RF818WgW7SUNev6pN6UUq3gvjmPjDTdZBZfiAZWY49nBLibPo2FvmyCP7tg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/cli": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.1.1.tgz", + "integrity": "sha512-Kzx+aUkAi8wx6m2e34Ekvyj9U46w7A3CHn6Zv+//TeplQitoMAzBOE8OiFVEcGJpi5gQ+NLDu0egfh2D+CC+ug==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1401.1", + "@angular-devkit/core": "14.1.1", + "@angular-devkit/schematics": "14.1.1", + "@schematics/angular": "14.1.1", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.1", + "resolve": "1.22.1", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@angular/common": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.1.1.tgz", + "integrity": "sha512-neFCnrIrGOuj3oOFBTLi4QrdI4fgKQprVLUEyL5LhCQ5R0K/F+gh61ovi7nT4XYnv41p4eqtG81YNMtVXH49pg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.1.1.tgz", + "integrity": "sha512-OT3cFfbHzLpl2M9qpO74oysXDkkKwlO66i4vlASMGf1/Qh+4UBh3iN6bls/ZbYZsl8bCr9zf0fL7c160e1uMcA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler-cli": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.1.1.tgz", + "integrity": "sha512-ERphqFDdN5u1XCZNV21DS0J9/WFZP/P4L4LQTjpEwbO/lDhzxaRnRnLOR6vGcetEHhRHMa0+OL8rrvNy6GwLmw==", + "requires": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "dependencies": { + "@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "requires": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@angular/core": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.1.1.tgz", + "integrity": "sha512-l3ms6/jxIUIeuCkXhz5nhRb94KLQ6wv9+B4lE0aJXcgHTqOmhc/ZIacT51LCjvVcok/vczF3f7w71Ii8b10yKQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/forms": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.1.1.tgz", + "integrity": "sha512-s4VuaivJ+s2hLlE8CMHLsAAmJNV/03EgBEJQV7rt1H0ogHs0jB/zlkzVw5K5bynCFkfIeDbwd6RvxzWhwE+ong==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/language-service": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.1.1.tgz", + "integrity": "sha512-bpUXsScvqzBodt94hEZdAHRZwHf3qqzadBcpTxJLoeJm69Q6hU1OdT7Id8wQfDESREUfbux12E1yVv7rEoIhJg==", + "dev": true + }, + "@angular/localize": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.1.1.tgz", + "integrity": "sha512-SUGTDJYcJoSJWaFcG12njbfnFreZZRnEr3Rs211wD3VSu4UJXrpP1hx2M/FoaHLZkcgpSSfkg/QHLDLYJLRL9Q==", + "requires": { + "@babel/core": "7.18.9", + "glob": "8.0.3", + "yargs": "^17.2.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@angular/platform-browser": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.1.1.tgz", + "integrity": "sha512-7yXr2GUiI1sD3kmKcWkHwlpmsRyA3WhwJqvjvMPQK4RD8ZeJ5LTOD6nQ4hz1kP19dfzpBDV/k9wusYDlmWtqcw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.1.1.tgz", + "integrity": "sha512-rD5KIWdxYRO2R0oGW6Ipt5pi+Cufws1704QBXhL52uaSJI6Ms7E7jvuwLG2SCJS0FJ+hdYLcuQZiQH+wUuyARA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/router": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.1.1.tgz", + "integrity": "sha512-yWgy4NXp0e4XxOXRwaY6YSlOseXoLCVp7jKeBGAqJXypT+HtWXwpWE12vPC8EvkdPLyrf+EuH3kNbSbLfUNtbw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" + }, + "@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "requires": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/generator": { + "version": "7.18.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", + "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "dev": true, + "requires": { + "@babel/types": "^7.18.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz", + "integrity": "sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", + "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", + "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + }, + "@babel/helper-wrap-function": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz", + "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" + }, + "dependencies": { + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + } + } + }, + "@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", + "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "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.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", + "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", + "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", + "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz", + "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz", + "integrity": "sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz", + "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-identifier": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", + "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz", + "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz", + "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz", + "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.6", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.6", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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.18.6", + "@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-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.6", + "@babel/plugin-transform-classes": "^7.18.6", + "@babel/plugin-transform-computed-properties": "^7.18.6", + "@babel/plugin-transform-destructuring": "^7.18.6", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.6", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.6", + "@babel/plugin-transform-function-name": "^7.18.6", + "@babel/plugin-transform-literals": "^7.18.6", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.6", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.6", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.6", + "@babel/plugin-transform-typeof-symbol": "^7.18.6", + "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.6", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@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" + } + }, + "@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/traverse": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz", + "integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.11", + "@babel/types": "^7.18.10", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "requires": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, + "@csstools/postcss-cascade-layers": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.0.5.tgz", + "integrity": "sha512-Id/9wBT7FkgFzdEpiEWrsVd4ltDxN0rI0QS0SChbeQiSuux3z21SJCRLu6h2cvCEUmaRi+VD0mHFj+GJD4GFnw==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "requires": {} + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@fortawesome/angular-fontawesome": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.11.1.tgz", + "integrity": "sha512-Ngzm5MVxk76ZhYpPTNOI/mpYNz9bzwfBXC5L9mktLgOONjBuYBPVt+bH8lny8hNtDk0ppZzXsMN6CO7hckdfnw==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + } + }, + "@fortawesome/free-brands-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz", + "integrity": "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + } + }, + "@fortawesome/free-regular-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz", + "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + } + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@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, + "requires": { + "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" + } + }, + "@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 + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@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==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-13.0.0.tgz", + "integrity": "sha512-aumflJ24VVOQ6kIGmpaWmjqfreRsXOCf/l2nOxPO6Y+d7Pit6aZthyjO7F0bRMutv6n+B/ma18GKvhhBcMepUw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ng-select/ng-select": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-9.0.2.tgz", + "integrity": "sha512-xdNiz/kgkMWYW1qFtk/337xDk/cmfEbSVtTFxWIM2OnIX1XsQOnTlGiBYces1TsMfqS68HjAvljEkj8QIGN2Lg==", + "requires": { + "tslib": "^2.3.1" + } + }, + "@ngtools/webpack": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.1.1.tgz", + "integrity": "sha512-pj8sN6jBIi2otTHE/CNQyy09Pmn8tGsZyFrSiNO147yjLnrOSJTeFuXfE2pYgrmcYgj0ybnK1zstt4bAKaL7/Q==", + "dev": true, + "requires": {} + }, + "@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ngx-translate/http-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-7.0.0.tgz", + "integrity": "sha512-j+NpXXlcGVdyUNyY/qsJrqqeAdJdizCd+GKh3usXExSqy1aE9866jlAIL+xrfDU4w+LiMoma5pgE4emvFebZmA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@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, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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 + }, + "@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, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.1.tgz", + "integrity": "sha512-1Q0uzx6c/NVNGszePbr5Gc2riSU1zLpNlo/1YWntH+eaPmMgBssAW0qXofCVkpdj3ce4swZtlDYQu+NKiYcptg==", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.1.tgz", + "integrity": "sha512-UU85F/T+F1oVn3IsB/L6k9zXIMpXBuUBE25QDH0SsURwT6IOBqkC7M16uqo2vVZIyji3X1K4XH9luip7YekH1A==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/move-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.0.tgz", + "integrity": "sha512-UR6D5f4KEGWJV6BGPH3Qb2EtgH+t+1XQ1Tt85c7qicN6cezzuHPdZwwAxqZr4JLtnQu0LZsTza/5gmNmSl8XLg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.0.tgz", + "integrity": "sha512-e/QgLg7j2wSJp1/7JRl0GC8c7PMX+uYlA/1Tb+IDOLdSM4T7K1VQ9mm9IGU3WRtY5vEIObpqCLb3aCNCug18DA==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "peer": true + }, + "@schematics/angular": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.1.1.tgz", + "integrity": "sha512-oSRDDhzg/27RKrQRoz09yELyBtsAFYfR1f+uq41FcmHZFfwOA5mQaqN2CQ1gUFygUZfZgOWSc+wma3ACIrwbHA==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.1.1", + "@angular-devkit/schematics": "14.1.1", + "jsonc-parser": "3.1.0" + } + }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "@types/eslint": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz", + "integrity": "sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "2.8.18", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.18.tgz", + "integrity": "sha512-CYOO2DsfoFnmYQ+tZyXsExePUomwvUhpSLEsM7kAJ5BSYNlom+5m3qZkxYrg2CoSfJ3tMv5NH02cB0y7GfjvaA==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", + "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/node": { + "version": "12.20.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz", + "integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "3.0.19", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz", + "integrity": "sha512-OFUilxQg+rWL2FMxtmIgCkUDlJB6pskkpvmew7yeXfzzsOBb5rc+y2+DjHm+r3r1ZPPcJefK3DveNSYWGiy68g==", + "dev": true + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "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, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "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 + }, + "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, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.8.tgz", + "integrity": "sha512-75Jr6Q/XpTqEf6D2ltS5uMewJIx5irCU1oBYJrWjFenq/m12WRRrz6g15L1EIoYvPLXTbEry7rDOwrcYNj77xw==", + "dev": true, + "requires": { + "browserslist": "^4.21.3", + "caniuse-lite": "^1.0.30001373", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "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, + "requires": { + "@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" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz", + "integrity": "sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.2", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + } + } + }, + "bonjour-service": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.13.tgz", + "integrity": "sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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 + }, + "bootstrap": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.1.tgz", + "integrity": "sha512-UQi3v2NpVPEi1n35dmRRzBJFlgvWHYwyem6yHhuT6afYF+sziEt46McRbT//kVXZ7b1YUYEVGdXEH74Nx3xzGA==", + "requires": {} + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "requires": { + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" + } + }, + "browserstack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + }, + "dependencies": { + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + } + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "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 + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacache": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.1.tgz", + "integrity": "sha512-VDKN+LHyCQXaaYZ7rA/qtkURU+/yYhviUdvqEv2LT6QPZU8jpyzEkEVAcKlKLt5dJ5BRp11ym8lo3NKLluEPLg==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001374", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz", + "integrity": "sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "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==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "common": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/common/-/common-0.2.5.tgz", + "integrity": "sha512-bjuztiY8Wcz2V9dPpa0XdF0unGWqAGsnyKDGV7g6xDcaZfpufRrxV35qhuhjwv1h0jEPeiCHWKAQFLj702jGnA==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "core-js-compat": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.1.tgz", + "integrity": "sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw==", + "dev": true, + "requires": { + "browserslist": "^4.21.3", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@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" + } + }, + "critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + }, + "dependencies": { + "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 + } + } + }, + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + } + }, + "css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "requires": {} + }, + "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, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "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 + }, + "cssdb": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-6.6.3.tgz", + "integrity": "sha512-7GDvDSmE+20+WcSMhP17Q1EVWUrLlbxxpMDqG731n8P99JhnQZHR9YvtjPvEHfjFUjvQJvdpKCjlKOX+xe4UVA==", + "dev": true + }, + "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 + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "dev": true + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "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, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.211", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz", + "integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==" + }, + "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==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dev": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + } + }, + "engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, + "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, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "esbuild": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", + "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "dev": true, + "optional": true, + "requires": { + "esbuild-android-64": "0.14.49", + "esbuild-android-arm64": "0.14.49", + "esbuild-darwin-64": "0.14.49", + "esbuild-darwin-arm64": "0.14.49", + "esbuild-freebsd-64": "0.14.49", + "esbuild-freebsd-arm64": "0.14.49", + "esbuild-linux-32": "0.14.49", + "esbuild-linux-64": "0.14.49", + "esbuild-linux-arm": "0.14.49", + "esbuild-linux-arm64": "0.14.49", + "esbuild-linux-mips64le": "0.14.49", + "esbuild-linux-ppc64le": "0.14.49", + "esbuild-linux-riscv64": "0.14.49", + "esbuild-linux-s390x": "0.14.49", + "esbuild-netbsd-64": "0.14.49", + "esbuild-openbsd-64": "0.14.49", + "esbuild-sunos-64": "0.14.49", + "esbuild-windows-32": "0.14.49", + "esbuild-windows-64": "0.14.49", + "esbuild-windows-arm64": "0.14.49" + } + }, + "esbuild-android-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", + "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", + "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", + "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", + "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", + "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", + "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", + "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", + "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", + "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", + "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", + "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", + "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", + "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", + "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", + "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", + "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", + "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.49.tgz", + "integrity": "sha512-5ddzZv8M3WI1fWZ5rEfK5cSA9swlWJcceKgqjKLLERC7FnlNW50kF7hxhpkyC0Z/4w7Xeyt3yUJ9QWNMDXLk2Q==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", + "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", + "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.49", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", + "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "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, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "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 + }, + "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, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "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 + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@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" + } + }, + "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 + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "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, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "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==" + }, + "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==" + }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "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 + }, + "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 + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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 + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "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 + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "hosted-git-info": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.0.0.tgz", + "integrity": "sha512-rRnjWu0Bxj+nIfUOkz0695C0H6tRrN5iYIzYejb0tDEefe2AekHu/U5Kn9pEie5vsJqpNQU02az7TGSH3qpz4Q==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "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 + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "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, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "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 + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "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, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, + "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, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "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 + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true + }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true + }, + "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 + }, + "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==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "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==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "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 + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", + "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "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, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "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 + } + } + }, + "istanbul-reports": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", + "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.8.0.tgz", + "integrity": "sha512-zl0nZWDrmbCiKns0NcjkFGYkVTGCPUgoHypTaj+G2AzaWus7QGoXARSlYsSle2VRpSdfJmM+hzmFKzQNhF2kHg==", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz", + "integrity": "sha512-6gP1LbVgJ+d7PKksQBc2H0oDGNRQI3gKUsWlswKaQ2fif9X5gzhQcgM5+kiJGCQVurOG09jqNhk7payggyp5+g==", + "dev": true, + "requires": { + "colors": "1.4.0" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "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, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "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 + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "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 + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "jszip": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", + "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "karma": { + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "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 + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "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" + } + }, + "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 + } + } + }, + "karma-chrome-launcher": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", + "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "dev": true, + "requires": { + "which": "^1.2.1" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", + "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^3.0.2", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.3.1.tgz", + "integrity": "sha512-Nxh7eX9mOQMyK0VSsMxdod+bcqrR/ikrmEiWj5M6fwuQ7oI+YEF1FckaDsWfs6TIpULm9f0fTKMjF7XcrvWyqQ==", + "dev": true, + "requires": { + "jasmine-core": "^3.5.0" + } + }, + "karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true, + "requires": {} + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "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 + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true + }, + "less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "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, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true + }, + "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, + "optional": true + } + } + }, + "less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "requires": { + "klona": "^2.0.4" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "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 + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "dev": true + }, + "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, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "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 + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + } + }, + "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==", + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.0.tgz", + "integrity": "sha512-OnEfCLofQVJ5zgKwGk55GaqosqKjaR6khQlJY3dBAA+hM25Bc5CmX5rKUfVut+rYA3uidA7zb7AvcglU87rPRg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.2.tgz", + "integrity": "sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==", + "dev": true + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "requires": { + "mime-db": "1.51.0" + } + }, + "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 + }, + "mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz", + "integrity": "sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "needle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", + "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-gyp": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.1.0.tgz", + "integrity": "sha512-HkmN0ZpQJU7FLbJauJTHkHlSVAXlNGDAzH/VYFZGDOnFyn/Na3GlNJfkudmufOdS6/jNFhy88ObzL7ERz9es1g==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.0.tgz", + "integrity": "sha512-m+GL22VXJKkKbw62ZaBBjv8u6IE3UI4Mh5QakIqs3fWiKe0Xyi6L97hakwZK41/LD4R/2ly71Bayx0NLMwLA/g==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "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 + }, + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "npm-packlist": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz", + "integrity": "sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^1.1.2", + "npm-normalize-package-bin": "^1.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.0.tgz", + "integrity": "sha512-10LJQ/1+VhKrZjIuY9I/+gQTvumqqlgnsCufoXETHAPFTS3+M+Z5CFhZRDHGavmJ6rOye3UvNga88vl8n1r6gg==", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + } + }, + "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, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "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, + "requires": { + "boolbase": "^1.0.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "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 + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "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, + "requires": { + "p-try": "^2.0.0" + } + }, + "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, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + } + } + }, + "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 + }, + "pacote": { + "version": "13.6.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz", + "integrity": "sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw==", + "dev": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "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, + "requires": { + "callsites": "^3.0.0" + } + }, + "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, + "requires": { + "@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" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "requires": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "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 + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "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 + }, + "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 + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "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 + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "requires": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" + } + }, + "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, + "requires": { + "find-up": "^4.0.0" + } + }, + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "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, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-properties": { + "version": "12.1.8", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.8.tgz", + "integrity": "sha512-8rbj8kVu00RQh2fQF81oBqtduiANu4MIxhyf0HbbStgPtnFlWn0yiaYTpLHrPnJbffVY1s9apWsIoVZcc68FxA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "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, + "requires": {} + }, + "postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "requires": {} + }, + "postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "requires": {} + }, + "postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "requires": {} + }, + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "requires": {} + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-nesting": { + "version": "10.1.10", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.10.tgz", + "integrity": "sha512-lqd7LXCq0gWc0wKXtoKDru5wEUNjm3OryLVNRZ8OnW8km6fSNUuFrjEhU3nklxXE2jvd4qrox566acgh+xQt8w==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-opacity-percentage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", + "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", + "dev": true + }, + "postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "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, + "requires": {} + }, + "postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-preset-env": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.7.2.tgz", + "integrity": "sha512-1q0ih7EDsZmCb/FMDRvosna7Gsbdx8CvYO5hYT120hcp2ZAuOHpSzibujZ4JpIUcAC02PG6b+eftxqjTFh5BNA==", + "dev": true, + "requires": { + "@csstools/postcss-cascade-layers": "^1.0.4", + "@csstools/postcss-color-function": "^1.1.0", + "@csstools/postcss-font-format-keywords": "^1.0.0", + "@csstools/postcss-hwb-function": "^1.0.1", + "@csstools/postcss-ic-unit": "^1.0.0", + "@csstools/postcss-is-pseudo-class": "^2.0.6", + "@csstools/postcss-normalize-display-values": "^1.0.0", + "@csstools/postcss-oklab-function": "^1.1.0", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.1", + "@csstools/postcss-unset-value": "^1.0.1", + "autoprefixer": "^10.4.7", + "browserslist": "^4.21.0", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^6.6.3", + "postcss-attribute-case-insensitive": "^5.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.3", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.0", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.4", + "postcss-double-position-gradients": "^3.1.1", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.3", + "postcss-image-set-function": "^4.0.6", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.0", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.9", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.3", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.4", + "postcss-pseudo-class-any-link": "^7.1.5", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "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, + "requires": {} + }, + "postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "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 + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "protractor": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "dev": true, + "requires": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "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" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "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 + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "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, + "requires": { + "pify": "^2.3.0" + } + }, + "read-package-json": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.1.tgz", + "integrity": "sha512-MALHuNgYWdGW3gKzuNMuYtcSSZbGQm94fAp16xt8VsYTLBjUSc55bLMKe6gzpWue0Tfi6CBgwCSdDAqutGDhMg==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "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 + }, + "regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", + "dev": true + }, + "regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "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 + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "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 + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "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 + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "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, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz", + "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + }, + "dependencies": { + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "selfsigned": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "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 + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socket.io": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + } + }, + "socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "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 + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "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, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "streamroller": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "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==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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 + }, + "stylus": { + "version": "0.58.1", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.58.1.tgz", + "integrity": "sha512-AYiCHm5ogczdCPMfe9aeQa4NklB2gcf4D/IhzYPddJjTgPc+k4D/EVE0yfQbZD43MHP3lPy+8NZ9fcFxkrgs/w==", + "dev": true, + "requires": { + "css": "^3.0.0", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + } + }, + "stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "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 + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz", + "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.7", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.7.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "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, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "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==" + }, + "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==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "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 + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + }, + "ua-parser-js": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "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, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + } + }, + "webdriver-manager": { + "version": "12.1.8", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.8.tgz", + "integrity": "sha512-qJR36SXG2VwKugPcdwhaqcLQOD7r8P2Xiv9sfNbfZrKBnX243iAkOueX1yAmeNgIKhJ3YAT/F2gq6IiEZzahsg==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "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" + } + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "webpack": { + "version": "5.73.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", + "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "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 + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", + "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "ws": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "dev": true, + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "requires": { + "typed-assert": "^1.0.8" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "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==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "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==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "requires": {} + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "requires": { + "cliui": "^7.0.2", + "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.0.0" + } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "zone.js": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.4.tgz", + "integrity": "sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw==", + "requires": { + "tslib": "^2.0.0" + } + } + } +} diff --git a/frontend/projects/public/package.json b/frontend/projects/public/package.json new file mode 100644 index 0000000000..7bedc6b915 --- /dev/null +++ b/frontend/projects/public/package.json @@ -0,0 +1,60 @@ +{ + "name": "alfio-public-frontend", + "version": "0.0.0", + "scripts": { + "source-map-explorer": "ng build --source-map=true && npx source-map-explorer dist/alfio-public-frontend/**/*.js", + "ng": "ng", + "start": "ng serve", + "startProd": "ng serve --aot=true --configuration production", + "build": "ng build --aot=true --configuration production", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "^14.1.1", + "@angular/common": "^14.1.1", + "@angular/compiler": "^14.1.1", + "@angular/core": "^14.1.1", + "@angular/forms": "^14.1.1", + "@angular/localize": "^14.1.1", + "@angular/platform-browser": "^14.1.1", + "@angular/platform-browser-dynamic": "^14.1.1", + "@angular/router": "^14.1.1", + "@fortawesome/angular-fontawesome": "^0.11.1", + "@fortawesome/fontawesome-svg-core": "^1.2.35", + "@fortawesome/free-brands-svg-icons": "^5.15.3", + "@fortawesome/free-regular-svg-icons": "^5.15.3", + "@fortawesome/free-solid-svg-icons": "^5.15.3", + "@ng-bootstrap/ng-bootstrap": "^13.0.0", + "@ng-select/ng-select": "^9.0.2", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "bootstrap": "^5.2.0", + "common": "^0.2.5", + "rxjs": "^6.6.3", + "tslib": "^2.0.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.1.1", + "@angular/cli": "^14.1.1", + "@angular/compiler-cli": "^14.1.1", + "@angular/language-service": "^14.1.1", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", + "jasmine-core": "~3.8.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~6.3.9", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~3.0.2", + "karma-jasmine": "~3.3.0", + "karma-jasmine-html-reporter": "^1.7.0", + "protractor": "~7.0.0", + "ts-node": "~7.0.0", + "tslint": "~6.1.0", + "typescript": "~4.7.4" + } +} diff --git a/frontend/projects/public/proxy.config.json b/frontend/projects/public/proxy.config.json new file mode 100644 index 0000000000..0beb1625a6 --- /dev/null +++ b/frontend/projects/public/proxy.config.json @@ -0,0 +1,36 @@ +{ + "/api": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + + "/file": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + + "/openid": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + + "/logout": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + + "/resources": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + } +} diff --git a/frontend/projects/public/src/app/additional-field/additional-field.component.html b/frontend/projects/public/src/app/additional-field/additional-field.component.html new file mode 100644 index 0000000000..43940714cc --- /dev/null +++ b/frontend/projects/public/src/app/additional-field/additional-field.component.html @@ -0,0 +1,39 @@ + +
+ + + + + + + + + + + + + +
+
+ {{' '}} + +
+
+
+
+ + +
+
+
+
+ {{ getRestrictedValueLabel(field.value) }} +
+
+
diff --git a/frontend/projects/public/src/app/additional-field/additional-field.component.ts b/frontend/projects/public/src/app/additional-field/additional-field.component.ts new file mode 100644 index 0000000000..55b3f4012c --- /dev/null +++ b/frontend/projects/public/src/app/additional-field/additional-field.component.ts @@ -0,0 +1,98 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {UntypedFormArray, UntypedFormGroup} from '@angular/forms'; +import {AdditionalField} from '../model/ticket'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../shared/i18n.service'; +import {LocalizedCountry} from '../model/localized-country'; +import {Subscription} from 'rxjs'; +import {mobile} from '../shared/util'; + +@Component({ + selector: 'app-additional-field', + templateUrl: './additional-field.component.html' +}) +export class AdditionalFieldComponent implements OnInit, OnDestroy { + + @Input() + field: AdditionalField; + + @Input() + form: UntypedFormGroup; + + @Input() + ticketUUID: string; + + @Input() + ticketAcquired: boolean; + + + countries: LocalizedCountry[]; + + isMobile = mobile; + + private langChangeSub: Subscription; + + constructor(private translate: TranslateService, private i18nService: I18nService) { } + + ngOnInit(): void { + if (this.field.type === 'country') { + this.getCountries(); + this.langChangeSub = this.translate.onLangChange.subscribe(() => { + this.getCountries(); + }); + } + } + + ngOnDestroy(): void { + if (this.langChangeSub) { + this.langChangeSub.unsubscribe(); + } + } + + get labelValue(): string { + if (this.field && this.field.description && this.field.description[this.translate.currentLang]) { + return this.field.description[this.translate.currentLang].label; + } else { + return ''; + } + } + + get placeholder(): string { + if (this.field && this.field.description && this.field.description[this.translate.currentLang]) { + return this.field.description[this.translate.currentLang].placeholder; + } else { + return ''; + } + } + + get editAllowed(): boolean { + return !this.ticketAcquired || this.field.value == null || this.field.value.trim().length === 0 || this.field.editable; + } + + getCountries(): void { + this.i18nService.getCountries(this.translate.currentLang).subscribe(countries => { + this.countries = countries; + }); + } + + getRestrictedValueLabel(value: string): string { + if (this.field.description[this.translate.currentLang]) { + return this.field.description[this.translate.currentLang].restrictedValuesDescription[value] || value; + } else { + return value; + } + } + + selectedCheckBox(index: number, value: string, checked: boolean) { + const fa = this.form.get(this.field.name) as UntypedFormArray; + fa.controls[index].setValue(checked ? value : null, {emitEvent: false, emitViewToModelChange: false}); + } + + get labelId(): string { + return this.ticketUUID + '-' + this.field.name.replace(/[^a-zA-Z0-9]/g, '+') + '-label'; + } + + get hideLabelForAssistiveTechnologies(): boolean { + return this.field.type === 'checkbox'; + } +} diff --git a/frontend/projects/public/src/app/additional-service-quantity-selector/additional-service-quantity-selector.component.ts b/frontend/projects/public/src/app/additional-service-quantity-selector/additional-service-quantity-selector.component.ts new file mode 100644 index 0000000000..56781a38c4 --- /dev/null +++ b/frontend/projects/public/src/app/additional-service-quantity-selector/additional-service-quantity-selector.component.ts @@ -0,0 +1,24 @@ +import {Component, Input} from '@angular/core'; +import {AdditionalService} from '../model/additional-service'; +import {Event} from '../model/event'; +import {UntypedFormGroup} from '@angular/forms'; + +@Component({ + selector: 'app-additional-service-quantity-selector', + templateUrl: './additional-service-quantity-selector.html' +}) +export class AdditionalServiceQuantitySelectorComponent { + + @Input() + additionalService: AdditionalService; + + @Input() + validSelectionValues: number[]; + + @Input() + event: Event; + + @Input() + parentGroup: UntypedFormGroup; + +} diff --git a/frontend/projects/public/src/app/additional-service-quantity-selector/additional-service-quantity-selector.html b/frontend/projects/public/src/app/additional-service-quantity-selector/additional-service-quantity-selector.html new file mode 100644 index 0000000000..8edc795455 --- /dev/null +++ b/frontend/projects/public/src/app/additional-service-quantity-selector/additional-service-quantity-selector.html @@ -0,0 +1,20 @@ +
+ +
+
+ +
+
+ +
+
+
+ +
+ {{event.currency}} +
+
+
+
diff --git a/frontend/projects/public/src/app/additional-service/additional-service.component.html b/frontend/projects/public/src/app/additional-service/additional-service.component.html new file mode 100644 index 0000000000..50ed713c97 --- /dev/null +++ b/frontend/projects/public/src/app/additional-service/additional-service.component.html @@ -0,0 +1,14 @@ +
+ + {{additionalService.title[translate.currentLang]}} +
+ + + + +
+
+ +
+
+
diff --git a/frontend/projects/public/src/app/additional-service/additional-service.component.scss b/frontend/projects/public/src/app/additional-service/additional-service.component.scss new file mode 100644 index 0000000000..d752af5199 --- /dev/null +++ b/frontend/projects/public/src/app/additional-service/additional-service.component.scss @@ -0,0 +1,11 @@ + +.append-currency { + font-size: 12px; + padding-left: 4px; + padding-right: 4px; +} + +h3.additional-service-title { + font-size: 1rem; + font-weight: bold; +} diff --git a/frontend/projects/public/src/app/additional-service/additional-service.component.ts b/frontend/projects/public/src/app/additional-service/additional-service.component.ts new file mode 100644 index 0000000000..98b6046733 --- /dev/null +++ b/frontend/projects/public/src/app/additional-service/additional-service.component.ts @@ -0,0 +1,70 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {AdditionalService} from '../model/additional-service'; +import {TranslateService} from '@ngx-translate/core'; +import {UntypedFormArray, UntypedFormBuilder, UntypedFormGroup} from '@angular/forms'; +import {Subscription} from 'rxjs'; +import {Event} from '../model/event'; + +@Component({ + selector: 'app-additional-service', + templateUrl: './additional-service.component.html', + styleUrls: ['./additional-service.component.scss'] +}) +export class AdditionalServiceComponent implements OnInit, OnDestroy { + + @Input() + additionalService: AdditionalService; + + @Input() + form: UntypedFormGroup; + + additionalServiceFormGroup: UntypedFormGroup; + + @Input() + event: Event; + + validSelectionValues: number[] = []; + + private formSub: Subscription; + + constructor(public translate: TranslateService, private formBuilder: UntypedFormBuilder) { } + + public ngOnInit(): void { + + const fa = this.form.get('additionalService') as UntypedFormArray; + + if (this.additionalService.fixPrice) { + this.additionalServiceFormGroup = this.formBuilder.group({additionalServiceId: this.additionalService.id, quantity: null}); + } else { + this.additionalServiceFormGroup = this.formBuilder.group({additionalServiceId: this.additionalService.id, amount: null}); + } + fa.push(this.additionalServiceFormGroup); + + // we only need to recalculate the select box choice in this specific supplement policy! + if (this.additionalService.supplementPolicy === 'OPTIONAL_MAX_AMOUNT_PER_TICKET') { + this.formSub = this.form.get('reservation').valueChanges.subscribe(valueChange => { + const selectedTicketCount = (valueChange as {amount: string}[]).map(a => parseInt(a.amount, 10)).reduce((sum, n) => sum + n, 0); + const rangeEnd = selectedTicketCount * this.additionalService.maxQtyPerOrder; + const res = []; + for (let i = 0; i <= rangeEnd; i++) { + res.push(i); + } + this.validSelectionValues = res; + }); + } else if (this.additionalService.supplementPolicy === 'OPTIONAL_MAX_AMOUNT_PER_RESERVATION' || + this.additionalService.supplementPolicy === null) { + const res = []; + for (let i = 0; i <= this.additionalService.maxQtyPerOrder; i++) { + res.push(i); + } + this.validSelectionValues = res; + } + } + + public ngOnDestroy(): void { + if (this.formSub) { + this.formSub.unsubscribe(); + } + } + +} diff --git a/frontend/projects/public/src/app/app-routing.module.ts b/frontend/projects/public/src/app/app-routing.module.ts new file mode 100644 index 0000000000..3ea4f41c10 --- /dev/null +++ b/frontend/projects/public/src/app/app-routing.module.ts @@ -0,0 +1,77 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {HomeComponent} from './home/home.component'; +import {EventDisplayComponent} from './event-display/event-display.component'; +import {BookingComponent} from './reservation/booking/booking.component'; +import {OverviewComponent} from './reservation/overview/overview.component'; +import {SuccessComponent} from './reservation/success/success.component'; +import {OfflinePaymentComponent} from './reservation/offline-payment/offline-payment.component'; +import {ViewTicketComponent} from './view-ticket/view-ticket.component'; +import {ReservationGuard} from './reservation/reservation.guard'; +import {ProcessingPaymentComponent} from './reservation/processing-payment/processing-payment.component'; +import {LanguageGuard} from './language.guard'; +import {NotFoundComponent} from './reservation/not-found/not-found.component'; +import {EventGuard} from './event.guard'; +import {ErrorComponent} from './reservation/error/error.component'; +import {DeferredOfflinePaymentComponent} from './reservation/deferred-offline-payment/deferred-offline-payment.component'; +import {UpdateTicketComponent} from './update-ticket/update-ticket.component'; +import {EventListAllComponent} from './event-list-all/event-list-all.component'; +import {SubscriptionListAllComponent} from './subscription-list-all/subscription-list-all.component'; +import {RemoveEventCssGuard} from './remove-event-css.guard'; +import {SubscriptionDisplayComponent} from './subscription-display/subscription-display.component'; +import {SuccessSubscriptionComponent} from './reservation/success-subscription/success-subscription.component'; +import {MyOrdersComponent} from './my-orders/my-orders.component'; +import {MyProfileComponent} from './my-profile/my-profile.component'; +import {UserLoggedInGuard} from './user-logged-in.guard'; +import {WaitingRoomComponent} from './waiting-room/waiting-room.component'; + +const eventReservationsGuard = [EventGuard, LanguageGuard, ReservationGuard]; +const eventData = {type: 'event', publicIdentifierParameter: 'eventShortName'}; +const subscriptionReservationsGuard = [LanguageGuard, ReservationGuard]; +const subscriptionData = {type: 'subscription', publicIdentifierParameter: 'id'}; + +const routes: Routes = [ + { path: '', component: HomeComponent, canActivate: [RemoveEventCssGuard, LanguageGuard] }, + { path: 'o/:organizerSlug', component: HomeComponent, canActivate: [RemoveEventCssGuard, LanguageGuard] }, + { path: 'o/:organizerSlug/events-all', component: EventListAllComponent, canActivate: [RemoveEventCssGuard, LanguageGuard] }, + { path: 'events-all', component: EventListAllComponent, canActivate: [RemoveEventCssGuard, LanguageGuard] }, + { path: 'subscriptions-all', component: SubscriptionListAllComponent, canActivate: [RemoveEventCssGuard, LanguageGuard]}, + { path: 'o/:organizerSlug/subscriptions-all', component: SubscriptionListAllComponent, canActivate: [RemoveEventCssGuard, LanguageGuard] }, + { path: 'subscription/:id', component: SubscriptionDisplayComponent, canActivate: [RemoveEventCssGuard, LanguageGuard], data: subscriptionData}, + { path: 'subscription/:id/reservation/:reservationId', data: subscriptionData, children: [ + { path: 'book', component: BookingComponent, canActivate: subscriptionReservationsGuard }, + { path: 'overview', component: OverviewComponent, canActivate: subscriptionReservationsGuard }, + { path: 'waiting-payment', component: OfflinePaymentComponent, canActivate: subscriptionReservationsGuard }, + { path: 'deferred-payment', component: DeferredOfflinePaymentComponent, canActivate: subscriptionReservationsGuard }, + { path: 'processing-payment', component: ProcessingPaymentComponent, canActivate: subscriptionReservationsGuard }, + { path: 'success', component: SuccessSubscriptionComponent, canActivate: subscriptionReservationsGuard }, + { path: 'not-found', component: NotFoundComponent, canActivate: subscriptionReservationsGuard }, + { path: 'error', component: ErrorComponent, canActivate: subscriptionReservationsGuard }, + ]}, + { path: 'event/:eventShortName', component: EventDisplayComponent, canActivate: [EventGuard, LanguageGuard], data: eventData}, + { path: 'event/:eventShortName/poll', loadChildren: () => import('./poll/poll.module').then(m => m.PollModule), canActivate: [EventGuard, LanguageGuard], data: eventData}, + { path: 'event/:eventShortName/reservation/:reservationId', data: eventData, children: [ + { path: 'book', component: BookingComponent, canActivate: eventReservationsGuard }, + { path: 'overview', component: OverviewComponent, canActivate: eventReservationsGuard }, + { path: 'waitingPayment', redirectTo: 'waiting-payment'}, + { path: 'waiting-payment', component: OfflinePaymentComponent, canActivate: eventReservationsGuard }, + { path: 'deferred-payment', component: DeferredOfflinePaymentComponent, canActivate: eventReservationsGuard }, + { path: 'processing-payment', component: ProcessingPaymentComponent, canActivate: eventReservationsGuard }, + { path: 'success', component: SuccessComponent, canActivate: eventReservationsGuard }, + { path: 'not-found', component: NotFoundComponent, canActivate: eventReservationsGuard }, + { path: 'error', component: ErrorComponent, canActivate: eventReservationsGuard }, + ]}, + { path: 'event/:eventShortName/ticket/:ticketId', data: eventData, children: [ + { path: 'view', component: ViewTicketComponent, canActivate: [EventGuard, LanguageGuard] }, + { path: 'update', component: UpdateTicketComponent, canActivate: [EventGuard, LanguageGuard] }, + { path: 'check-in/:ticketCodeHash/waiting-room', component: WaitingRoomComponent, canActivate: [EventGuard, LanguageGuard] } + ]}, + { path: 'my-orders', component: MyOrdersComponent, canActivate: [UserLoggedInGuard, RemoveEventCssGuard, LanguageGuard] }, + { path: 'my-profile', component: MyProfileComponent, canActivate: [UserLoggedInGuard, RemoveEventCssGuard, LanguageGuard] } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/frontend/projects/public/src/app/app.component.html b/frontend/projects/public/src/app/app.component.html new file mode 100644 index 0000000000..4d70c44d66 --- /dev/null +++ b/frontend/projects/public/src/app/app.component.html @@ -0,0 +1,3 @@ + + + diff --git a/frontend/projects/public/src/app/app.component.ts b/frontend/projects/public/src/app/app.component.ts new file mode 100644 index 0000000000..0cab2c3af2 --- /dev/null +++ b/frontend/projects/public/src/app/app.component.ts @@ -0,0 +1,29 @@ +import {Component, OnDestroy} from '@angular/core'; +import {TranslateService} from '@ngx-translate/core'; +import {Subscription} from 'rxjs'; +import {I18nService} from './shared/i18n.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html' +}) +export class AppComponent implements OnDestroy { + + private readonly langChangeSub: Subscription; + + constructor(translate: TranslateService, i18nService: I18nService) { + const defaultLang = document.getElementsByTagName('html')[0].getAttribute('lang'); + translate.setDefaultLang(defaultLang); + + this.langChangeSub = translate.onLangChange.subscribe(langChange => { + document.getElementsByTagName('html')[0].setAttribute('lang', langChange.lang); + i18nService.persistLanguage(langChange.lang); + }); + } + + public ngOnDestroy(): void { + if (this.langChangeSub) { + this.langChangeSub.unsubscribe(); + } + } +} diff --git a/frontend/projects/public/src/app/app.module.ts b/frontend/projects/public/src/app/app.module.ts new file mode 100644 index 0000000000..9b072c6fa7 --- /dev/null +++ b/frontend/projects/public/src/app/app.module.ts @@ -0,0 +1,228 @@ +import {BrowserModule} from '@angular/platform-browser'; +import {AlfioCommonModule} from 'common'; +import {APP_INITIALIZER, NgModule} from '@angular/core'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; + +import {AppRoutingModule} from './app-routing.module'; +import {AppComponent} from './app.component'; +import {HomeComponent} from './home/home.component'; +import {EventDisplayComponent} from './event-display/event-display.component'; +import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule, HttpClientXsrfModule, HttpXsrfTokenExtractor} from '@angular/common/http'; + +import {FaIconLibrary, FontAwesomeModule} from '@fortawesome/angular-fontawesome'; +import { + faAddressCard, + faAngleDown, + faAngleUp, + faCheck, + faCircle, + faCog, + faCreditCard, + faDownload, + faEraser, + faExchangeAlt, + faExclamationCircle, + faExclamationTriangle, + faExternalLinkAlt, + faFileAlt, + faFileInvoice, + faGift, + faGlobe, + faInfoCircle, + faMapMarkerAlt, + faMoneyBill, + faMoneyCheckAlt, + faRedoAlt, + faSearchPlus, + faSignInAlt, + faSignOutAlt, + faThumbsUp, + faTicketAlt, + faTimes, + faTrash, + faUserAstronaut, + faWifi, + faFilePdf +} from '@fortawesome/free-solid-svg-icons'; +import {faBuilding, faCalendarAlt, faCalendarPlus, faCheckCircle, faClock, faClone, faCompass, faCopy, faEdit, faEnvelope, faHandshake} from '@fortawesome/free-regular-svg-icons'; +import {faApplePay, faIdeal, faPaypal, faStripe} from '@fortawesome/free-brands-svg-icons'; +import {TranslateLoader, TranslateModule} from '@ngx-translate/core'; +import {NgbDropdownModule, NgbModalModule, NgbTooltipModule} from '@ng-bootstrap/ng-bootstrap'; +import {NgSelectModule} from '@ng-select/ng-select'; + +import {BookingComponent} from './reservation/booking/booking.component'; +import {OverviewComponent} from './reservation/overview/overview.component'; +import {SuccessComponent} from './reservation/success/success.component'; +import {ReservationComponent} from './reservation/reservation.component'; +import {StepperComponent} from './stepper/stepper.component'; +import {AdditionalFieldComponent} from './additional-field/additional-field.component'; +import {ViewTicketComponent} from './view-ticket/view-ticket.component'; +import {UpdateTicketComponent} from './update-ticket/update-ticket.component'; +import {EventSummaryComponent} from './event-summary/event-summary.component'; +import {TicketFormComponent} from './reservation/ticket-form/ticket-form.component'; +import {CountdownComponent} from './countdown/countdown.component'; +import {BannerCheckComponent} from './banner-check/banner-check.component'; +import {OfflinePaymentComponent} from './reservation/offline-payment/offline-payment.component'; +import {OfflinePaymentProxyComponent} from './payment/offline-payment-proxy/offline-payment-proxy.component'; +import {OnsitePaymentProxyComponent} from './payment/onsite-payment-proxy/onsite-payment-proxy.component'; +import {PaypalPaymentProxyComponent} from './payment/paypal-payment-proxy/paypal-payment-proxy.component'; +import {StripePaymentProxyComponent} from './payment/stripe-payment-proxy/stripe-payment-proxy.component'; +import {SaferpayPaymentProxyComponent} from './payment/saferpay-payment-proxy/saferpay-payment-proxy.component'; +import {ProcessingPaymentComponent} from './reservation/processing-payment/processing-payment.component'; +import {SummaryTableComponent} from './reservation/summary-table/summary-table.component'; +import {InvoiceFormComponent} from './reservation/invoice-form/invoice-form.component'; +import {AdditionalServiceComponent} from './additional-service/additional-service.component'; +import {RecaptchaComponent} from './recaptcha/recaptcha.component'; +import {CustomLoader} from './shared/i18n.service'; +import {NotFoundComponent} from './reservation/not-found/not-found.component'; +import {PriceTagComponent} from './price-tag/price-tag.component'; +import {TicketQuantitySelectorComponent} from './ticket-quantity-selector/ticket-quantity-selector.component'; +import {ItemSalePeriodComponent} from './category-sale-period/item-sale-period.component'; +import {ItemCardComponent} from './item-card/item-card.component'; +import {AdditionalServiceQuantitySelectorComponent} from './additional-service-quantity-selector/additional-service-quantity-selector.component'; +import {ReservationExpiredComponent} from './reservation/expired-notification/reservation-expired.component'; +import {ReleaseTicketComponent} from './reservation/release-ticket/release-ticket.component'; +import {CancelReservationComponent} from './reservation/cancel-reservation/cancel-reservation.component'; +import {FooterLinksComponent} from './event-footer-links/footer-links.component'; +import {ErrorComponent} from './reservation/error/error.component'; +import {DeferredOfflinePaymentComponent} from './reservation/deferred-offline-payment/deferred-offline-payment.component'; +import {MolliePaymentProxyComponent} from './payment/mollie-payment-proxy/mollie-payment-proxy.component'; +import {PaymentMethodSelectorComponent} from './reservation/payment-method-selector/payment-method-selector.component'; +import {AnimatedDotsComponent} from './reservation/animated-dots/animated-dots.component'; +import {EventDatesComponent} from './event-dates/event-dates.component'; +import {SharedModule} from './shared/shared.module'; +import {EventListAllComponent} from './event-list-all/event-list-all.component'; +import {BasicEventInfoComponent} from './basic-event-info/basic-event-info.component'; +import {SubscriptionListAllComponent} from './subscription-list-all/subscription-list-all.component'; +import {SubscriptionDisplayComponent} from './subscription-display/subscription-display.component'; +import {SuccessSubscriptionComponent} from './reservation/success-subscription/success-subscription.component'; +import {BasicSubscriptionInfoComponent} from './basic-subscription-info/basic-subscription-info.component'; +import {SubscriptionSummaryComponent} from './subscription-summary/subscription-summary.component'; +import {PurchaseContextContainerComponent} from './purchase-context-container/purchase-context-container.component'; +import {ModalRemoveSubscriptionComponent} from './reservation/modal-remove-subscription/modal-remove-subscription.component'; +import {UserService} from './shared/user.service'; +import {MyOrdersComponent} from './my-orders/my-orders.component'; +import {MyProfileComponent} from './my-profile/my-profile.component'; +import {WaitingRoomComponent} from './waiting-room/waiting-room.component'; +import {MyProfileDeleteWarningComponent} from './my-profile/my-profile-delete-warning.component'; +import {TranslateDescriptionPipe} from './shared/translate-description.pipe'; +// import { AuthTokenInterceptor, DOMGidExtractor, DOMXsrfTokenExtractor } from 'common'; // FIXME: check why importing from common fail +import { AuthTokenInterceptor, DOMGidExtractor, DOMXsrfTokenExtractor } from './xsrf'; +import {DownloadTicketComponent} from './reservation/download-ticket/download-ticket.component'; + + + +// AoT requires an exported function for factories +export function HttpLoaderFactory(http: HttpClient) { + return new CustomLoader(http); +} + +export function InitUserService(userService: UserService): () => Promise { + return () => userService.initAuthenticationStatus(); +} + +@NgModule({ + declarations: [ + AppComponent, + HomeComponent, + EventDisplayComponent, + BookingComponent, + OverviewComponent, + SuccessComponent, + ReservationComponent, + StepperComponent, + AdditionalFieldComponent, + ViewTicketComponent, + UpdateTicketComponent, + EventSummaryComponent, + TicketFormComponent, + DownloadTicketComponent, + CountdownComponent, + BannerCheckComponent, + OfflinePaymentComponent, + OfflinePaymentProxyComponent, + OnsitePaymentProxyComponent, + PaypalPaymentProxyComponent, + StripePaymentProxyComponent, + SaferpayPaymentProxyComponent, + ProcessingPaymentComponent, + SummaryTableComponent, + InvoiceFormComponent, + AdditionalServiceComponent, + RecaptchaComponent, + PriceTagComponent, + NotFoundComponent, + TicketQuantitySelectorComponent, + ItemSalePeriodComponent, + ItemCardComponent, + AdditionalServiceQuantitySelectorComponent, + ReservationExpiredComponent, + ReleaseTicketComponent, + CancelReservationComponent, + FooterLinksComponent, + ErrorComponent, + DeferredOfflinePaymentComponent, + MolliePaymentProxyComponent, + PaymentMethodSelectorComponent, + AnimatedDotsComponent, + EventDatesComponent, + EventListAllComponent, + BasicEventInfoComponent, + BasicSubscriptionInfoComponent, + SubscriptionListAllComponent, + SubscriptionDisplayComponent, + SuccessSubscriptionComponent, + SubscriptionSummaryComponent, + PurchaseContextContainerComponent, + ModalRemoveSubscriptionComponent, + MyOrdersComponent, + MyProfileComponent, + WaitingRoomComponent, + MyProfileDeleteWarningComponent, + TranslateDescriptionPipe + ], + imports: [ + BrowserModule, + AppRoutingModule, + HttpClientModule, + HttpClientXsrfModule.withOptions({ + cookieName: 'XSRF-TOKEN', + headerName: 'X-CSRF-TOKEN', + }), + FontAwesomeModule, + FormsModule, + ReactiveFormsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }), + NgbTooltipModule, + NgSelectModule, + NgbModalModule, + NgbDropdownModule, + SharedModule, + AlfioCommonModule, + ], + providers: [ + { provide: APP_INITIALIZER, useFactory: InitUserService, deps: [UserService], multi: true }, + { provide: HTTP_INTERCEPTORS, useClass: AuthTokenInterceptor, multi: true }, + { provide: HttpXsrfTokenExtractor, useClass: DOMXsrfTokenExtractor }, + DOMGidExtractor, + DOMXsrfTokenExtractor, + AuthTokenInterceptor + ], + bootstrap: [AppComponent] +}) +export class AppModule { + constructor(library: FaIconLibrary) { + library.addIcons(faInfoCircle, faGift, faTicketAlt, faCheck, faAddressCard, faFileAlt, faThumbsUp, faMoneyBill, + faDownload, faSearchPlus, faExchangeAlt, faExclamationTriangle, faCreditCard, faCog, faEraser, faTimes, faFileInvoice, faGlobe, + faAngleDown, faAngleUp, faCircle, faCheckCircle, faMoneyCheckAlt, faWifi, faTrash, faCopy, faExclamationCircle, faUserAstronaut, + faSignInAlt, faSignOutAlt, faExternalLinkAlt, faMapMarkerAlt, faRedoAlt); + library.addIcons(faCalendarAlt, faCalendarPlus, faCompass, faClock, faEnvelope, faEdit, faClone, faHandshake, faBuilding); + library.addIcons(faPaypal, faStripe, faIdeal, faApplePay, faFilePdf); + } +} diff --git a/frontend/projects/public/src/app/banner-check/banner-check.component.html b/frontend/projects/public/src/app/banner-check/banner-check.component.html new file mode 100644 index 0000000000..409633e289 --- /dev/null +++ b/frontend/projects/public/src/app/banner-check/banner-check.component.html @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/projects/public/src/app/banner-check/banner-check.component.scss b/frontend/projects/public/src/app/banner-check/banner-check.component.scss new file mode 100644 index 0000000000..c8b1bf7098 --- /dev/null +++ b/frontend/projects/public/src/app/banner-check/banner-check.component.scss @@ -0,0 +1,11 @@ +.banner { + position: sticky; + top: 0; + width: 100%; + margin: 0; + border-bottom: none; + border-left: none; + border-right: none; + border-radius: 0; + z-index: 100; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/banner-check/banner-check.component.ts b/frontend/projects/public/src/app/banner-check/banner-check.component.ts new file mode 100644 index 0000000000..20ee1650e7 --- /dev/null +++ b/frontend/projects/public/src/app/banner-check/banner-check.component.ts @@ -0,0 +1,35 @@ +import {Component, OnInit} from '@angular/core'; +import {InfoService} from '../shared/info.service'; +import {Info} from '../model/info'; +import {getFromSessionStorage, writeToSessionStorage} from '../shared/util'; + +const hideAnnouncementBannerKey = 'alfio.hideAnnouncementBanner'; + +@Component({ + selector: 'app-banner-check', + templateUrl: './banner-check.component.html', + styleUrls: ['./banner-check.component.scss'] +}) +export class BannerCheckComponent implements OnInit { + + info: Info; + secure: boolean; + hideAlertInfo: boolean; + hideAnnouncementBanner: boolean; + + constructor(private infoService: InfoService) { } + + ngOnInit() { + this.hideAnnouncementBanner = !!getFromSessionStorage(hideAnnouncementBannerKey); + this.infoService.getInfo().subscribe(info => { + this.info = info; + this.secure = location.protocol.indexOf('https:') === 0; + }); + } + + dismissAnnouncementBanner(): void { + this.hideAnnouncementBanner = true; + writeToSessionStorage(hideAnnouncementBannerKey, 'true'); + } + +} diff --git a/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.html b/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.html new file mode 100644 index 0000000000..d4b6cc87d4 --- /dev/null +++ b/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.html @@ -0,0 +1,18 @@ +
+
+ +
{{'event.online.badge' | translate}}
+
+
+

{{title}}

+ +
+   {{event.location}} +
+
+ +
diff --git a/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.scss b/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.scss new file mode 100644 index 0000000000..713c4cb752 --- /dev/null +++ b/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.scss @@ -0,0 +1,25 @@ +.event-header { + height: 100px; + overflow: hidden; + background-position: top center; + background-repeat: no-repeat; + display: flex; + flex-direction: row; + align-items: center; +} + +.event-header > img { + position: relative; + max-height: 80px; + width: auto; +} + +a.no-decoration:hover { + text-decoration:none; +} + +.online-flag { + position: absolute; + top: 10px; + right: 10px; +} diff --git a/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.ts b/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.ts new file mode 100644 index 0000000000..74339d0ead --- /dev/null +++ b/frontend/projects/public/src/app/basic-event-info/basic-event-info.component.ts @@ -0,0 +1,34 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {BasicEventInfo} from '../model/basic-event-info'; +import {TranslateService} from '@ngx-translate/core'; +import {Params} from '@angular/router'; +import {getLocalizedContent} from '../shared/subscription.service'; + +@Component({ + selector: 'app-basic-event-info', + templateUrl: './basic-event-info.component.html', + styleUrls: ['./basic-event-info.component.scss'] +}) +export class BasicEventInfoComponent implements OnInit { + + @Input() + event: BasicEventInfo; + + @Input() + params: Params; + + constructor(private translateService: TranslateService) { } + + ngOnInit(): void { + } + + + public get isEventOnline(): boolean { + return this.event.format === 'ONLINE'; + } + + get title(): string { + return getLocalizedContent(this.event.title, this.translateService.currentLang); + } + +} diff --git a/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.html b/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.html new file mode 100644 index 0000000000..6dbd3012f8 --- /dev/null +++ b/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.html @@ -0,0 +1,16 @@ +
+
+ +
+
+

{{title}}

+
+ +
+
+ +
diff --git a/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.scss b/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.scss new file mode 100644 index 0000000000..713c4cb752 --- /dev/null +++ b/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.scss @@ -0,0 +1,25 @@ +.event-header { + height: 100px; + overflow: hidden; + background-position: top center; + background-repeat: no-repeat; + display: flex; + flex-direction: row; + align-items: center; +} + +.event-header > img { + position: relative; + max-height: 80px; + width: auto; +} + +a.no-decoration:hover { + text-decoration:none; +} + +.online-flag { + position: absolute; + top: 10px; + right: 10px; +} diff --git a/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.ts b/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.ts new file mode 100644 index 0000000000..c0670c4a4f --- /dev/null +++ b/frontend/projects/public/src/app/basic-subscription-info/basic-subscription-info.component.ts @@ -0,0 +1,33 @@ +import {Component, Input} from '@angular/core'; +import {BasicSubscriptionInfo} from '../model/subscription'; +import {TranslateService} from '@ngx-translate/core'; +import {getLocalizedContent} from '../shared/subscription.service'; +import {SubscriptionOwner} from '../model/reservation-info'; +import {Params} from '@angular/router'; + +@Component({ + selector: 'app-basic-subscription-info', + templateUrl: './basic-subscription-info.component.html', + styleUrls: ['./basic-subscription-info.component.scss'] +}) +export class BasicSubscriptionInfoComponent { + @Input() + subscription: BasicSubscriptionInfo; + @Input() + owner?: SubscriptionOwner; + @Input() + params: Params; + + @Input() + cardLayout = true; + + constructor(private translateService: TranslateService) {} + + get title(): string { + return getLocalizedContent(this.subscription.title, this.translateService.currentLang); + } + + get description(): string { + return getLocalizedContent(this.subscription.description, this.translateService.currentLang); + } +} diff --git a/frontend/projects/public/src/app/category-sale-period/item-sale-period.component.ts b/frontend/projects/public/src/app/category-sale-period/item-sale-period.component.ts new file mode 100644 index 0000000000..290600986c --- /dev/null +++ b/frontend/projects/public/src/app/category-sale-period/item-sale-period.component.ts @@ -0,0 +1,14 @@ +import {Component, Input} from '@angular/core'; +import {TicketCategory} from '../model/ticket-category'; +import {AdditionalService} from '../model/additional-service'; + +@Component({ + selector: 'app-item-sale-period', + templateUrl: './item-sale-period.html' +}) +export class ItemSalePeriodComponent { + @Input() + item: TicketCategory | AdditionalService; + @Input() + currentLang: string; +} diff --git a/frontend/projects/public/src/app/category-sale-period/item-sale-period.html b/frontend/projects/public/src/app/category-sale-period/item-sale-period.html new file mode 100644 index 0000000000..4596b3adb2 --- /dev/null +++ b/frontend/projects/public/src/app/category-sale-period/item-sale-period.html @@ -0,0 +1,5 @@ + +
{{'show-event.sales-not-started'|translate: {'0': item.formattedInception[currentLang]} }}
+
{{'show-event.sales-end'|translate: {'0': item.formattedExpiration[currentLang]} }}
+
{{'show-event.sales-ended'|translate: {'0': item.formattedExpiration[currentLang]} }}
+ diff --git a/frontend/projects/public/src/app/countdown/countdown.component.html b/frontend/projects/public/src/app/countdown/countdown.component.html new file mode 100644 index 0000000000..c88bc76a69 --- /dev/null +++ b/frontend/projects/public/src/app/countdown/countdown.component.html @@ -0,0 +1,5 @@ +
+ {{' '}} + + +
\ No newline at end of file diff --git a/frontend/projects/public/src/app/countdown/countdown.component.ts b/frontend/projects/public/src/app/countdown/countdown.component.ts new file mode 100644 index 0000000000..b1ad7dbed5 --- /dev/null +++ b/frontend/projects/public/src/app/countdown/countdown.component.ts @@ -0,0 +1,76 @@ +import {Component, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core'; +import {TranslateService} from '@ngx-translate/core'; +import * as countdown from './countdown'; // see issue: https://stackoverflow.com/a/70506557 + https://github.com/mckamey/countdownjs/issues/39 +import {Subscription} from 'rxjs'; + +@Component({ + selector: 'app-countdown', + templateUrl: './countdown.component.html', + styleUrls: ['./countdown.scss'] +}) +export class CountdownComponent implements OnInit, OnDestroy { + + @Input() + validity: number; + + @Output() + expired: EventEmitter = new EventEmitter(); + + timerId: number; + + message: string; + isExpired: boolean; + alertType = 'info'; + displaySticky = false; + + private langChangeSub: Subscription; + + constructor(private translateService: TranslateService) { } + + ngOnInit() { + this.setupCountdown(); + + this.langChangeSub = this.translateService.onLangChange.subscribe(e => { + this.setupCountdown(); + }); + } + + ngOnDestroy() { + if (this.langChangeSub) { + this.langChangeSub.unsubscribe(); + } + clearInterval(this.timerId); + } + + private setupCountdown(): void { + + clearInterval(this.timerId); + + const msg = this.translateService.instant('reservation-page.time-for-completion'); + const singular = this.translateService.instant('reservation-page.time-for-completion.labels.singular'); + const plural = this.translateService.instant('reservation-page.time-for-completion.labels.plural'); + const and = this.translateService.instant('reservation-page.time-for-completion.labels.and'); + const oneSecond = 1000; + const oneMinute = 60 * oneSecond; + const fiveMinutes = 5 * oneMinute; + + countdown.setLabels(singular, plural, ' ' + and + ' ', ', '); + this.timerId = countdown(new Date(this.validity), (ts) => { + const absDifference = Math.abs(ts.value); + if (ts.value < 0 && absDifference >= oneSecond) { + if (absDifference < fiveMinutes) { + this.alertType = absDifference < oneMinute ? 'danger' : 'warning'; + this.displaySticky = true; + } + this.message = msg.replace('##time##', ts.toHTML('strong')); + } else { + this.isExpired = true; + this.alertType = 'danger'; + clearInterval(this.timerId); + this.expired.emit(true); + } + // tslint:disable-next-line: no-bitwise + }, countdown.MONTHS | countdown.WEEKS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS) as number; + } + +} diff --git a/frontend/projects/public/src/app/countdown/countdown.js b/frontend/projects/public/src/app/countdown/countdown.js new file mode 100644 index 0000000000..7920bb3ce7 --- /dev/null +++ b/frontend/projects/public/src/app/countdown/countdown.js @@ -0,0 +1,1357 @@ +/*global window module */ +/** + * @license countdown.js v2.6.1 http://countdownjs.org + * Copyright (c)2006-2014 Stephen M. McKamey. + * Licensed under The MIT License. + */ +/*jshint bitwise:false */ + +/** + * API entry + * @public + * @param {function(Object)|Date|number} start the starting date + * @param {function(Object)|Date|number} end the ending date + * @param {number} units the units to populate + * @return {Object|number} + */ + var countdown = ( + + function() { + /*jshint smarttabs:true */ + + 'use strict'; + + /** + * @private + * @const + * @type {number} + */ + var MILLISECONDS = 0x001; + + /** + * @private + * @const + * @type {number} + */ + var SECONDS = 0x002; + + /** + * @private + * @const + * @type {number} + */ + var MINUTES = 0x004; + + /** + * @private + * @const + * @type {number} + */ + var HOURS = 0x008; + + /** + * @private + * @const + * @type {number} + */ + var DAYS = 0x010; + + /** + * @private + * @const + * @type {number} + */ + var WEEKS = 0x020; + + /** + * @private + * @const + * @type {number} + */ + var MONTHS = 0x040; + + /** + * @private + * @const + * @type {number} + */ + var YEARS = 0x080; + + /** + * @private + * @const + * @type {number} + */ + var DECADES = 0x100; + + /** + * @private + * @const + * @type {number} + */ + var CENTURIES = 0x200; + + /** + * @private + * @const + * @type {number} + */ + var MILLENNIA = 0x400; + + /** + * @private + * @const + * @type {number} + */ + var DEFAULTS = YEARS|MONTHS|DAYS|HOURS|MINUTES|SECONDS; + + /** + * @private + * @const + * @type {number} + */ + var MILLISECONDS_PER_SECOND = 1000; + + /** + * @private + * @const + * @type {number} + */ + var SECONDS_PER_MINUTE = 60; + + /** + * @private + * @const + * @type {number} + */ + var MINUTES_PER_HOUR = 60; + + /** + * @private + * @const + * @type {number} + */ + var HOURS_PER_DAY = 24; + + /** + * @private + * @const + * @type {number} + */ + var MILLISECONDS_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND; + + /** + * @private + * @const + * @type {number} + */ + var DAYS_PER_WEEK = 7; + + /** + * @private + * @const + * @type {number} + */ + var MONTHS_PER_YEAR = 12; + + /** + * @private + * @const + * @type {number} + */ + var YEARS_PER_DECADE = 10; + + /** + * @private + * @const + * @type {number} + */ + var DECADES_PER_CENTURY = 10; + + /** + * @private + * @const + * @type {number} + */ + var CENTURIES_PER_MILLENNIUM = 10; + + /** + * @private + * @param {number} x number + * @return {number} + */ + var ceil = Math.ceil; + + /** + * @private + * @param {number} x number + * @return {number} + */ + var floor = Math.floor; + + /** + * @private + * @param {Date} ref reference date + * @param {number} shift number of months to shift + * @return {number} number of days shifted + */ + function borrowMonths(ref, shift) { + var prevTime = ref.getTime(); + + // increment month by shift + ref.setMonth( ref.getMonth() + shift ); + + // this is the trickiest since months vary in length + return Math.round( (ref.getTime() - prevTime) / MILLISECONDS_PER_DAY ); + } + + /** + * @private + * @param {Date} ref reference date + * @return {number} number of days + */ + function daysPerMonth(ref) { + var a = ref.getTime(); + + // increment month by 1 + var b = new Date(a); + b.setMonth( ref.getMonth() + 1 ); + + // this is the trickiest since months vary in length + return Math.round( (b.getTime() - a) / MILLISECONDS_PER_DAY ); + } + + /** + * @private + * @param {Date} ref reference date + * @return {number} number of days + */ + function daysPerYear(ref) { + var a = ref.getTime(); + + // increment year by 1 + var b = new Date(a); + b.setFullYear( ref.getFullYear() + 1 ); + + // this is the trickiest since years (periodically) vary in length + return Math.round( (b.getTime() - a) / MILLISECONDS_PER_DAY ); + } + + /** + * Applies the Timespan to the given date. + * + * @private + * @param {Timespan} ts + * @param {Date=} date + * @return {Date} + */ + function addToDate(ts, date) { + date = (date instanceof Date) || ((date !== null) && isFinite(date)) ? new Date(+date) : new Date(); + if (!ts) { + return date; + } + + // if there is a value field, use it directly + var value = +ts.value || 0; + if (value) { + date.setTime(date.getTime() + value); + return date; + } + + value = +ts.milliseconds || 0; + if (value) { + date.setMilliseconds(date.getMilliseconds() + value); + } + + value = +ts.seconds || 0; + if (value) { + date.setSeconds(date.getSeconds() + value); + } + + value = +ts.minutes || 0; + if (value) { + date.setMinutes(date.getMinutes() + value); + } + + value = +ts.hours || 0; + if (value) { + date.setHours(date.getHours() + value); + } + + value = +ts.weeks || 0; + if (value) { + value *= DAYS_PER_WEEK; + } + + value += +ts.days || 0; + if (value) { + date.setDate(date.getDate() + value); + } + + value = +ts.months || 0; + if (value) { + date.setMonth(date.getMonth() + value); + } + + value = +ts.millennia || 0; + if (value) { + value *= CENTURIES_PER_MILLENNIUM; + } + + value += +ts.centuries || 0; + if (value) { + value *= DECADES_PER_CENTURY; + } + + value += +ts.decades || 0; + if (value) { + value *= YEARS_PER_DECADE; + } + + value += +ts.years || 0; + if (value) { + date.setFullYear(date.getFullYear() + value); + } + + return date; + } + + /** + * @private + * @const + * @type {number} + */ + var LABEL_MILLISECONDS = 0; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_SECONDS = 1; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_MINUTES = 2; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_HOURS = 3; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_DAYS = 4; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_WEEKS = 5; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_MONTHS = 6; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_YEARS = 7; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_DECADES = 8; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_CENTURIES = 9; + + /** + * @private + * @const + * @type {number} + */ + var LABEL_MILLENNIA = 10; + + /** + * @private + * @type {Array} + */ + var LABELS_SINGLUAR; + + /** + * @private + * @type {Array} + */ + var LABELS_PLURAL; + + /** + * @private + * @type {string} + */ + var LABEL_LAST; + + /** + * @private + * @type {string} + */ + var LABEL_DELIM; + + /** + * @private + * @type {string} + */ + var LABEL_NOW; + + /** + * Formats a number & unit as a string + * + * @param {number} value + * @param {number} unit + * @return {string} + */ + var formatter; + + /** + * Formats a number as a string + * + * @private + * @param {number} value + * @return {string} + */ + var formatNumber; + + /** + * @private + * @param {number} value + * @param {number} unit unit index into label list + * @return {string} + */ + function plurality(value, unit) { + return formatNumber(value)+((value === 1) ? LABELS_SINGLUAR[unit] : LABELS_PLURAL[unit]); + } + + /** + * Formats the entries with singular or plural labels + * + * @private + * @param {Timespan} ts + * @return {Array} + */ + var formatList; + + /** + * Timespan representation of a duration of time + * + * @private + * @this {Timespan} + * @constructor + */ + function Timespan() {} + + /** + * Formats the Timespan as a sentence + * + * @param {string=} emptyLabel the string to use when no values returned + * @return {string} + */ + Timespan.prototype.toString = function(emptyLabel) { + var label = formatList(this); + + var count = label.length; + if (!count) { + return emptyLabel ? ''+emptyLabel : LABEL_NOW; + } + if (count === 1) { + return label[0]; + } + + var last = LABEL_LAST+label.pop(); + return label.join(LABEL_DELIM)+last; + }; + + /** + * Formats the Timespan as a sentence in HTML + * + * @param {string=} tag HTML tag name to wrap each value + * @param {string=} emptyLabel the string to use when no values returned + * @return {string} + */ + Timespan.prototype.toHTML = function(tag, emptyLabel) { + tag = tag || 'span'; + var label = formatList(this); + + var count = label.length; + if (!count) { + emptyLabel = emptyLabel || LABEL_NOW; + return emptyLabel ? '<'+tag+'>'+emptyLabel+'' : emptyLabel; + } + for (var i=0; i'+label[i]+''; + } + if (count === 1) { + return label[0]; + } + + var last = LABEL_LAST+label.pop(); + return label.join(LABEL_DELIM)+last; + }; + + /** + * Applies the Timespan to the given date + * + * @param {Date=} date the date to which the timespan is added. + * @return {Date} + */ + Timespan.prototype.addTo = function(date) { + return addToDate(this, date); + }; + + /** + * Formats the entries as English labels + * + * @private + * @param {Timespan} ts + * @return {Array} + */ + formatList = function(ts) { + var list = []; + + var value = ts.millennia; + if (value) { + list.push(formatter(value, LABEL_MILLENNIA)); + } + + value = ts.centuries; + if (value) { + list.push(formatter(value, LABEL_CENTURIES)); + } + + value = ts.decades; + if (value) { + list.push(formatter(value, LABEL_DECADES)); + } + + value = ts.years; + if (value) { + list.push(formatter(value, LABEL_YEARS)); + } + + value = ts.months; + if (value) { + list.push(formatter(value, LABEL_MONTHS)); + } + + value = ts.weeks; + if (value) { + list.push(formatter(value, LABEL_WEEKS)); + } + + value = ts.days; + if (value) { + list.push(formatter(value, LABEL_DAYS)); + } + + value = ts.hours; + if (value) { + list.push(formatter(value, LABEL_HOURS)); + } + + value = ts.minutes; + if (value) { + list.push(formatter(value, LABEL_MINUTES)); + } + + value = ts.seconds; + if (value) { + list.push(formatter(value, LABEL_SECONDS)); + } + + value = ts.milliseconds; + if (value) { + list.push(formatter(value, LABEL_MILLISECONDS)); + } + + return list; + }; + + /** + * Borrow any underflow units, carry any overflow units + * + * @private + * @param {Timespan} ts + * @param {string} toUnit + */ + function rippleRounded(ts, toUnit) { + switch (toUnit) { + case 'seconds': + if (ts.seconds !== SECONDS_PER_MINUTE || isNaN(ts.minutes)) { + return; + } + // ripple seconds up to minutes + ts.minutes++; + ts.seconds = 0; + + /* falls through */ + case 'minutes': + if (ts.minutes !== MINUTES_PER_HOUR || isNaN(ts.hours)) { + return; + } + // ripple minutes up to hours + ts.hours++; + ts.minutes = 0; + + /* falls through */ + case 'hours': + if (ts.hours !== HOURS_PER_DAY || isNaN(ts.days)) { + return; + } + // ripple hours up to days + ts.days++; + ts.hours = 0; + + /* falls through */ + case 'days': + if (ts.days !== DAYS_PER_WEEK || isNaN(ts.weeks)) { + return; + } + // ripple days up to weeks + ts.weeks++; + ts.days = 0; + + /* falls through */ + case 'weeks': + if (ts.weeks !== daysPerMonth(ts.refMonth)/DAYS_PER_WEEK || isNaN(ts.months)) { + return; + } + // ripple weeks up to months + ts.months++; + ts.weeks = 0; + + /* falls through */ + case 'months': + if (ts.months !== MONTHS_PER_YEAR || isNaN(ts.years)) { + return; + } + // ripple months up to years + ts.years++; + ts.months = 0; + + /* falls through */ + case 'years': + if (ts.years !== YEARS_PER_DECADE || isNaN(ts.decades)) { + return; + } + // ripple years up to decades + ts.decades++; + ts.years = 0; + + /* falls through */ + case 'decades': + if (ts.decades !== DECADES_PER_CENTURY || isNaN(ts.centuries)) { + return; + } + // ripple decades up to centuries + ts.centuries++; + ts.decades = 0; + + /* falls through */ + case 'centuries': + if (ts.centuries !== CENTURIES_PER_MILLENNIUM || isNaN(ts.millennia)) { + return; + } + // ripple centuries up to millennia + ts.millennia++; + ts.centuries = 0; + /* falls through */ + } + } + + /** + * Ripple up partial units one place + * + * @private + * @param {Timespan} ts timespan + * @param {number} frac accumulated fractional value + * @param {string} fromUnit source unit name + * @param {string} toUnit target unit name + * @param {number} conversion multiplier between units + * @param {number} digits max number of decimal digits to output + * @return {number} new fractional value + */ + function fraction(ts, frac, fromUnit, toUnit, conversion, digits) { + if (ts[fromUnit] >= 0) { + frac += ts[fromUnit]; + delete ts[fromUnit]; + } + + frac /= conversion; + if (frac + 1 <= 1) { + // drop if below machine epsilon + return 0; + } + + if (ts[toUnit] >= 0) { + // ensure does not have more than specified number of digits + ts[toUnit] = +(ts[toUnit] + frac).toFixed(digits); + rippleRounded(ts, toUnit); + return 0; + } + + return frac; + } + + /** + * Ripple up partial units to next existing + * + * @private + * @param {Timespan} ts + * @param {number} digits max number of decimal digits to output + */ + function fractional(ts, digits) { + var frac = fraction(ts, 0, 'milliseconds', 'seconds', MILLISECONDS_PER_SECOND, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'seconds', 'minutes', SECONDS_PER_MINUTE, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'minutes', 'hours', MINUTES_PER_HOUR, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'hours', 'days', HOURS_PER_DAY, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'days', 'weeks', DAYS_PER_WEEK, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'weeks', 'months', daysPerMonth(ts.refMonth)/DAYS_PER_WEEK, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'months', 'years', daysPerYear(ts.refMonth)/daysPerMonth(ts.refMonth), digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'years', 'decades', YEARS_PER_DECADE, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'decades', 'centuries', DECADES_PER_CENTURY, digits); + if (!frac) { return; } + + frac = fraction(ts, frac, 'centuries', 'millennia', CENTURIES_PER_MILLENNIUM, digits); + + // should never reach this with remaining fractional value + if (frac) { throw new Error('Fractional unit overflow'); } + } + + /** + * Borrow any underflow units, carry any overflow units + * + * @private + * @param {Timespan} ts + */ + function ripple(ts) { + var x; + + if (ts.milliseconds < 0) { + // ripple seconds down to milliseconds + x = ceil(-ts.milliseconds / MILLISECONDS_PER_SECOND); + ts.seconds -= x; + ts.milliseconds += x * MILLISECONDS_PER_SECOND; + + } else if (ts.milliseconds >= MILLISECONDS_PER_SECOND) { + // ripple milliseconds up to seconds + ts.seconds += floor(ts.milliseconds / MILLISECONDS_PER_SECOND); + ts.milliseconds %= MILLISECONDS_PER_SECOND; + } + + if (ts.seconds < 0) { + // ripple minutes down to seconds + x = ceil(-ts.seconds / SECONDS_PER_MINUTE); + ts.minutes -= x; + ts.seconds += x * SECONDS_PER_MINUTE; + + } else if (ts.seconds >= SECONDS_PER_MINUTE) { + // ripple seconds up to minutes + ts.minutes += floor(ts.seconds / SECONDS_PER_MINUTE); + ts.seconds %= SECONDS_PER_MINUTE; + } + + if (ts.minutes < 0) { + // ripple hours down to minutes + x = ceil(-ts.minutes / MINUTES_PER_HOUR); + ts.hours -= x; + ts.minutes += x * MINUTES_PER_HOUR; + + } else if (ts.minutes >= MINUTES_PER_HOUR) { + // ripple minutes up to hours + ts.hours += floor(ts.minutes / MINUTES_PER_HOUR); + ts.minutes %= MINUTES_PER_HOUR; + } + + if (ts.hours < 0) { + // ripple days down to hours + x = ceil(-ts.hours / HOURS_PER_DAY); + ts.days -= x; + ts.hours += x * HOURS_PER_DAY; + + } else if (ts.hours >= HOURS_PER_DAY) { + // ripple hours up to days + ts.days += floor(ts.hours / HOURS_PER_DAY); + ts.hours %= HOURS_PER_DAY; + } + + while (ts.days < 0) { + // NOTE: never actually seen this loop more than once + + // ripple months down to days + ts.months--; + ts.days += borrowMonths(ts.refMonth, 1); + } + + // weeks is always zero here + + if (ts.days >= DAYS_PER_WEEK) { + // ripple days up to weeks + ts.weeks += floor(ts.days / DAYS_PER_WEEK); + ts.days %= DAYS_PER_WEEK; + } + + if (ts.months < 0) { + // ripple years down to months + x = ceil(-ts.months / MONTHS_PER_YEAR); + ts.years -= x; + ts.months += x * MONTHS_PER_YEAR; + + } else if (ts.months >= MONTHS_PER_YEAR) { + // ripple months up to years + ts.years += floor(ts.months / MONTHS_PER_YEAR); + ts.months %= MONTHS_PER_YEAR; + } + + // years is always non-negative here + // decades, centuries and millennia are always zero here + + if (ts.years >= YEARS_PER_DECADE) { + // ripple years up to decades + ts.decades += floor(ts.years / YEARS_PER_DECADE); + ts.years %= YEARS_PER_DECADE; + + if (ts.decades >= DECADES_PER_CENTURY) { + // ripple decades up to centuries + ts.centuries += floor(ts.decades / DECADES_PER_CENTURY); + ts.decades %= DECADES_PER_CENTURY; + + if (ts.centuries >= CENTURIES_PER_MILLENNIUM) { + // ripple centuries up to millennia + ts.millennia += floor(ts.centuries / CENTURIES_PER_MILLENNIUM); + ts.centuries %= CENTURIES_PER_MILLENNIUM; + } + } + } + } + + /** + * Remove any units not requested + * + * @private + * @param {Timespan} ts + * @param {number} units the units to populate + * @param {number} max number of labels to output + * @param {number} digits max number of decimal digits to output + */ + function pruneUnits(ts, units, max, digits) { + var count = 0; + + // Calc from largest unit to smallest to prevent underflow + if (!(units & MILLENNIA) || (count >= max)) { + // ripple millennia down to centuries + ts.centuries += ts.millennia * CENTURIES_PER_MILLENNIUM; + delete ts.millennia; + + } else if (ts.millennia) { + count++; + } + + if (!(units & CENTURIES) || (count >= max)) { + // ripple centuries down to decades + ts.decades += ts.centuries * DECADES_PER_CENTURY; + delete ts.centuries; + + } else if (ts.centuries) { + count++; + } + + if (!(units & DECADES) || (count >= max)) { + // ripple decades down to years + ts.years += ts.decades * YEARS_PER_DECADE; + delete ts.decades; + + } else if (ts.decades) { + count++; + } + + if (!(units & YEARS) || (count >= max)) { + // ripple years down to months + ts.months += ts.years * MONTHS_PER_YEAR; + delete ts.years; + + } else if (ts.years) { + count++; + } + + if (!(units & MONTHS) || (count >= max)) { + // ripple months down to days + if (ts.months) { + ts.days += borrowMonths(ts.refMonth, ts.months); + } + delete ts.months; + + if (ts.days >= DAYS_PER_WEEK) { + // ripple day overflow back up to weeks + ts.weeks += floor(ts.days / DAYS_PER_WEEK); + ts.days %= DAYS_PER_WEEK; + } + + } else if (ts.months) { + count++; + } + + if (!(units & WEEKS) || (count >= max)) { + // ripple weeks down to days + ts.days += ts.weeks * DAYS_PER_WEEK; + delete ts.weeks; + + } else if (ts.weeks) { + count++; + } + + if (!(units & DAYS) || (count >= max)) { + //ripple days down to hours + ts.hours += ts.days * HOURS_PER_DAY; + delete ts.days; + + } else if (ts.days) { + count++; + } + + if (!(units & HOURS) || (count >= max)) { + // ripple hours down to minutes + ts.minutes += ts.hours * MINUTES_PER_HOUR; + delete ts.hours; + + } else if (ts.hours) { + count++; + } + + if (!(units & MINUTES) || (count >= max)) { + // ripple minutes down to seconds + ts.seconds += ts.minutes * SECONDS_PER_MINUTE; + delete ts.minutes; + + } else if (ts.minutes) { + count++; + } + + if (!(units & SECONDS) || (count >= max)) { + // ripple seconds down to milliseconds + ts.milliseconds += ts.seconds * MILLISECONDS_PER_SECOND; + delete ts.seconds; + + } else if (ts.seconds) { + count++; + } + + // nothing to ripple milliseconds down to + // so ripple back up to smallest existing unit as a fractional value + if (!(units & MILLISECONDS) || (count >= max)) { + fractional(ts, digits); + } + } + + /** + * Populates the Timespan object + * + * @private + * @param {Timespan} ts + * @param {?Date} start the starting date + * @param {?Date} end the ending date + * @param {number} units the units to populate + * @param {number} max number of labels to output + * @param {number} digits max number of decimal digits to output + */ + function populate(ts, start, end, units, max, digits) { + var now = new Date(); + + ts.start = start = start || now; + ts.end = end = end || now; + ts.units = units; + + ts.value = end.getTime() - start.getTime(); + if (ts.value < 0) { + // swap if reversed + var tmp = end; + end = start; + start = tmp; + } + + // reference month for determining days in month + ts.refMonth = new Date(start.getFullYear(), start.getMonth(), 15, 12, 0, 0); + try { + // reset to initial deltas + ts.millennia = 0; + ts.centuries = 0; + ts.decades = 0; + ts.years = end.getFullYear() - start.getFullYear(); + ts.months = end.getMonth() - start.getMonth(); + ts.weeks = 0; + ts.days = end.getDate() - start.getDate(); + ts.hours = end.getHours() - start.getHours(); + ts.minutes = end.getMinutes() - start.getMinutes(); + ts.seconds = end.getSeconds() - start.getSeconds(); + ts.milliseconds = end.getMilliseconds() - start.getMilliseconds(); + + ripple(ts); + pruneUnits(ts, units, max, digits); + + } finally { + delete ts.refMonth; + } + + return ts; + } + + /** + * Determine an appropriate refresh rate based upon units + * + * @private + * @param {number} units the units to populate + * @return {number} milliseconds to delay + */ + function getDelay(units) { + if (units & MILLISECONDS) { + // refresh very quickly + return MILLISECONDS_PER_SECOND / 30; //30Hz + } + + if (units & SECONDS) { + // refresh every second + return MILLISECONDS_PER_SECOND; //1Hz + } + + if (units & MINUTES) { + // refresh every minute + return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE; + } + + if (units & HOURS) { + // refresh hourly + return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR; + } + + if (units & DAYS) { + // refresh daily + return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY; + } + + // refresh the rest weekly + return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * DAYS_PER_WEEK; + } + + /** + * API entry point + * + * @public + * @param {Date|number|Timespan|null|function(Timespan,number)} start the starting date + * @param {Date|number|Timespan|null|function(Timespan,number)} end the ending date + * @param {number=} units the units to populate + * @param {number=} max number of labels to output + * @param {number=} digits max number of decimal digits to output + * @return {Timespan|number} + */ + function countdown(start, end, units, max, digits) { + var callback; + + // ensure some units or use defaults + units = +units || DEFAULTS; + // max must be positive + max = (max > 0) ? max : NaN; + // clamp digits to an integer between [0, 20] + digits = (digits > 0) ? (digits < 20) ? Math.round(digits) : 20 : 0; + + // ensure start date + var startTS = null; + if ('function' === typeof start) { + callback = start; + start = null; + + } else if (!(start instanceof Date)) { + if ((start !== null) && isFinite(start)) { + start = new Date(+start); + } else { + if ('object' === typeof startTS) { + startTS = /** @type{Timespan} */(start); + } + start = null; + } + } + + // ensure end date + var endTS = null; + if ('function' === typeof end) { + callback = end; + end = null; + + } else if (!(end instanceof Date)) { + if ((end !== null) && isFinite(end)) { + end = new Date(+end); + } else { + if ('object' === typeof end) { + endTS = /** @type{Timespan} */(end); + } + end = null; + } + } + + // must wait to interpret timespans until after resolving dates + if (startTS) { + start = addToDate(startTS, end); + } + if (endTS) { + end = addToDate(endTS, start); + } + + if (!start && !end) { + // used for unit testing + return new Timespan(); + } + + if (!callback) { + return populate(new Timespan(), /** @type{Date} */(start), /** @type{Date} */(end), /** @type{number} */(units), /** @type{number} */(max), /** @type{number} */(digits)); + } + + // base delay off units + var delay = getDelay(units), + timerId, + fn = function() { + callback( + populate(new Timespan(), /** @type{Date} */(start), /** @type{Date} */(end), /** @type{number} */(units), /** @type{number} */(max), /** @type{number} */(digits)), + timerId + ); + }; + + fn(); + return (timerId = setInterval(fn, delay)); + } + + /** + * @public + * @const + * @type {number} + */ + countdown.MILLISECONDS = MILLISECONDS; + + /** + * @public + * @const + * @type {number} + */ + countdown.SECONDS = SECONDS; + + /** + * @public + * @const + * @type {number} + */ + countdown.MINUTES = MINUTES; + + /** + * @public + * @const + * @type {number} + */ + countdown.HOURS = HOURS; + + /** + * @public + * @const + * @type {number} + */ + countdown.DAYS = DAYS; + + /** + * @public + * @const + * @type {number} + */ + countdown.WEEKS = WEEKS; + + /** + * @public + * @const + * @type {number} + */ + countdown.MONTHS = MONTHS; + + /** + * @public + * @const + * @type {number} + */ + countdown.YEARS = YEARS; + + /** + * @public + * @const + * @type {number} + */ + countdown.DECADES = DECADES; + + /** + * @public + * @const + * @type {number} + */ + countdown.CENTURIES = CENTURIES; + + /** + * @public + * @const + * @type {number} + */ + countdown.MILLENNIA = MILLENNIA; + + /** + * @public + * @const + * @type {number} + */ + countdown.DEFAULTS = DEFAULTS; + + /** + * @public + * @const + * @type {number} + */ + countdown.ALL = MILLENNIA|CENTURIES|DECADES|YEARS|MONTHS|WEEKS|DAYS|HOURS|MINUTES|SECONDS|MILLISECONDS; + + /** + * Customize the format settings. + * @public + * @param {Object} format settings object + */ + var setFormat = countdown.setFormat = function(format) { + if (!format) { return; } + + if ('singular' in format || 'plural' in format) { + var singular = format.singular || []; + if (singular.split) { + singular = singular.split('|'); + } + var plural = format.plural || []; + if (plural.split) { + plural = plural.split('|'); + } + + for (var i=LABEL_MILLISECONDS; i<=LABEL_MILLENNIA; i++) { + // override any specified units + LABELS_SINGLUAR[i] = singular[i] || LABELS_SINGLUAR[i]; + LABELS_PLURAL[i] = plural[i] || LABELS_PLURAL[i]; + } + } + + if ('string' === typeof format.last) { + LABEL_LAST = format.last; + } + if ('string' === typeof format.delim) { + LABEL_DELIM = format.delim; + } + if ('string' === typeof format.empty) { + LABEL_NOW = format.empty; + } + if ('function' === typeof format.formatNumber) { + formatNumber = format.formatNumber; + } + if ('function' === typeof format.formatter) { + formatter = format.formatter; + } + }; + + /** + * Revert to the default formatting. + * @public + */ + var resetFormat = countdown.resetFormat = function() { + LABELS_SINGLUAR = ' millisecond| second| minute| hour| day| week| month| year| decade| century| millennium'.split('|'); + LABELS_PLURAL = ' milliseconds| seconds| minutes| hours| days| weeks| months| years| decades| centuries| millennia'.split('|'); + LABEL_LAST = ' and '; + LABEL_DELIM = ', '; + LABEL_NOW = ''; + formatNumber = function(value) { return value; }; + formatter = plurality; + }; + + /** + * Override the unit labels. + * @public + * @param {string|Array=} singular a pipe ('|') delimited list of singular unit name overrides + * @param {string|Array=} plural a pipe ('|') delimited list of plural unit name overrides + * @param {string=} last a delimiter before the last unit (default: ' and ') + * @param {string=} delim a delimiter to use between all other units (default: ', ') + * @param {string=} empty a label to use when all units are zero (default: '') + * @param {function(number):string=} formatNumber a function which formats numbers as a string + * @param {function(number,number):string=} formatter a function which formats a number/unit pair as a string + * @deprecated since version 2.6.0 + */ + countdown.setLabels = function(singular, plural, last, delim, empty, formatNumber, formatter) { + setFormat({ + singular: singular, + plural: plural, + last: last, + delim: delim, + empty: empty, + formatNumber: formatNumber, + formatter: formatter + }); + }; + + /** + * Revert to the default unit labels. + * @public + * @deprecated since version 2.6.0 + */ + countdown.resetLabels = resetFormat; + + resetFormat(); + + if (typeof module !== 'undefined' && module.exports) { + module.exports = countdown; + + } else if (typeof window !== 'undefined' && typeof window.define === 'function' && typeof window.define.amd !== 'undefined') { + window.define('countdown', [], function() { + return countdown; + }); + } + + return countdown; + + })(); \ No newline at end of file diff --git a/frontend/projects/public/src/app/countdown/countdown.scss b/frontend/projects/public/src/app/countdown/countdown.scss new file mode 100644 index 0000000000..e7dfc5dd8e --- /dev/null +++ b/frontend/projects/public/src/app/countdown/countdown.scss @@ -0,0 +1,7 @@ +div.sticky { + position: -webkit-sticky; + position: sticky; + top: 0px; + left: 0px; + z-index: 200; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/event-dates/event-dates.component.html b/frontend/projects/public/src/app/event-dates/event-dates.component.html new file mode 100644 index 0000000000..37c86777ff --- /dev/null +++ b/frontend/projects/public/src/app/event-dates/event-dates.component.html @@ -0,0 +1,24 @@ + + +   + {{' ' + dateValidityProvider.formattedBeginDate[translate.currentLang]}} {{'event-days.single-day.hours'|translate: {'0': dateValidityProvider.formattedBeginTime[translate.currentLang], '1': dateValidityProvider.formattedEndTime[translate.currentLang]} }} +   ({{dateValidityProvider.timeZone}}) + + +
+
+
+
+
+ + {{localizedStartDateForMultiDay}} +   ({{dateValidityProvider.timeZone}}) +
+
+ + {{localizedEndDateForMultiDay}} +   ({{dateValidityProvider.timeZone}}) +
+
+
+
diff --git a/frontend/projects/public/src/app/event-dates/event-dates.component.ts b/frontend/projects/public/src/app/event-dates/event-dates.component.ts new file mode 100644 index 0000000000..fff13d2f1c --- /dev/null +++ b/frontend/projects/public/src/app/event-dates/event-dates.component.ts @@ -0,0 +1,36 @@ +import {Component, Input} from '@angular/core'; +import {DateValidity} from '../model/date-validity'; +import {shouldDisplayTimeZoneInfo} from '../shared/event.service'; +import {TranslateService} from '@ngx-translate/core'; + + +@Component({ + selector: 'app-event-dates', + templateUrl: './event-dates.component.html' +}) +export class EventDatesComponent { + @Input() + dateValidityProvider: DateValidity; + @Input() + displayIcon: boolean; + + constructor(public translate: TranslateService) { } + + get displayTimeZoneInfo(): boolean { + return shouldDisplayTimeZoneInfo(this.dateValidityProvider); + } + + get localizedStartDateForMultiDay(): string { + return this.translate.instant('event-days.not-same-day', { + '0': this.dateValidityProvider.formattedBeginDate[this.translate.currentLang], + '1': this.dateValidityProvider.formattedBeginTime[this.translate.currentLang] + }); + } + + get localizedEndDateForMultiDay(): string { + return this.translate.instant('event-days.not-same-day', { + '0': this.dateValidityProvider.formattedEndDate[this.translate.currentLang], + '1': this.dateValidityProvider.formattedEndTime[this.translate.currentLang] + }); + } +} diff --git a/frontend/projects/public/src/app/event-display/event-display.component.html b/frontend/projects/public/src/app/event-display/event-display.component.html new file mode 100644 index 0000000000..37ec67654f --- /dev/null +++ b/frontend/projects/public/src/app/event-display/event-display.component.html @@ -0,0 +1,216 @@ + +
+
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+ +
+

{{'show-event.tickets' | translate}} {{"show-event.tickets.left" | translate: {'0': event.availableTicketsCount} }}

+ + + + + + + +
+ + +
+ + +
+ +
+ + + {{category.name}} + +
+ {{'event.online.badge' | translate}} + {{"show-event.tickets.left" | translate: {'0': category.availableTickets} }} +
+
+ + + + +
+
+ +
+
+
+ +
+
+ +
+
    +
  • +
    +
    +
    + {{category.name}} +
    +
    +
    +
    {{'show-event.sales-ended'|translate: {'0': category.formattedExpiration[translate.currentLang]} }}
    +
    +
    +
  • +
+
+ + + +
+

+ +
+ +
+

+ +
+ +
+
+
+
{{' '}}{{'show-event.promo-code-applied' | translate: {'0': (event.promotionsConfiguration.usePartnerCode ? 'show-event.promo-code-type.partner' : 'show-event.promo-code-type.promotional') | translate} }} {{eventCode.code}}
+

+ + {{'show-event.promo-code-fixed-amount-discount'|translate: {'0': eventCode.discountAmount + ' ' + event.currency} }} + + + {{'show-event.promo-code-percentage-discount'|translate: {'0': eventCode.discountAmount + ' ' + event.currency} }} + + + {{'show-event.promo-code-percentage-discount'|translate: {'0': eventCode.discountAmount + '%'} }} + +

+
+
+ +
+
+
+ + +
+
+ +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + + +
+ +
+
+
+
+
+ +
+
+
diff --git a/frontend/projects/public/src/app/event-display/event-display.component.scss b/frontend/projects/public/src/app/event-display/event-display.component.scss new file mode 100644 index 0000000000..54036659c8 --- /dev/null +++ b/frontend/projects/public/src/app/event-display/event-display.component.scss @@ -0,0 +1,19 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; + +.promo-code-input { + margin-left: 0.5rem; + margin-right: 0.5rem; +} + +.margin-auto { + margin: auto; +} + +.badge-block { + display: block; +} + +.text-muted .btn-link { + color: $text-muted; +} diff --git a/frontend/projects/public/src/app/event-display/event-display.component.ts b/frontend/projects/public/src/app/event-display/event-display.component.ts new file mode 100644 index 0000000000..22b1e040df --- /dev/null +++ b/frontend/projects/public/src/app/event-display/event-display.component.ts @@ -0,0 +1,301 @@ +import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {EventService} from '../shared/event.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {UntypedFormArray, UntypedFormBuilder, UntypedFormGroup} from '@angular/forms'; +import {ReservationService} from '../shared/reservation.service'; +import {Event as AlfioEvent} from '../model/event'; +import {TranslateService} from '@ngx-translate/core'; +import {TicketCategory} from '../model/ticket-category'; +import {ReservationRequest} from '../model/reservation-request'; +import {handleServerSideValidationError} from '../shared/validation-helper'; +import {zip} from 'rxjs'; +import {AdditionalService} from '../model/additional-service'; +import {I18nService} from '../shared/i18n.service'; +import {WaitingListSubscriptionRequest} from '../model/waiting-list-subscription-request'; +import {ItemsByCategory, TicketCategoryForWaitingList} from '../model/items-by-category'; +import {DynamicDiscount, EventCode} from '../model/event-code'; +import {AnalyticsService} from '../shared/analytics.service'; +import {ErrorDescriptor} from '../model/validated-response'; +import {SearchParams} from '../model/search-params'; + +@Component({ + selector: 'app-event-display', + templateUrl: './event-display.component.html', + styleUrls: ['./event-display.component.scss'] +}) +export class EventDisplayComponent implements OnInit { + + event: AlfioEvent; + ticketCategories: TicketCategory[]; + expiredCategories: TicketCategory[]; + // + supplementCategories: AdditionalService[]; + donationCategories: AdditionalService[]; + // + reservationForm: UntypedFormGroup; + globalErrors: ErrorDescriptor[] = []; + // + ticketCategoryAmount: {[key: number]: number[]}; + // + + // + preSales: boolean; + waitingList: boolean; + ticketCategoriesForWaitingList: TicketCategoryForWaitingList[]; + waitingListForm: UntypedFormGroup; + waitingListRequestSubmitted: boolean; + waitingListRequestResult: boolean; + // + + eventCode: EventCode; + eventCodeError: boolean; + + displayPromoCodeForm: boolean; + promoCodeForm: UntypedFormGroup; + @ViewChild('promoCode') + promoCodeElement: ElementRef; + @ViewChild('tickets') + tickets: ElementRef; + expiredCategoriesExpanded = false; + + private dynamicDiscount: DynamicDiscount; + + // https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/ + + constructor( + private route: ActivatedRoute, + private router: Router, + private eventService: EventService, + private reservationService: ReservationService, + private formBuilder: UntypedFormBuilder, + public translate: TranslateService, + private i18nService: I18nService, + private analytics: AnalyticsService) { } + + ngOnInit(): void { + + const code = this.route.snapshot.queryParams['code']; + const errors = this.route.snapshot.queryParams['errors']; + if (errors) { + this.globalErrors = errors.split(',').map(val => { const ed = new ErrorDescriptor(); ed.code = val; return ed; }); + } + + this.route.params.subscribe(params => { + const eventShortName = params['eventShortName']; + + zip(this.eventService.getEvent(eventShortName), this.eventService.getEventTicketsInfo(eventShortName)).subscribe( ([event, itemsByCat]) => { + this.event = event; + + this.i18nService.setPageTitle('show-event.header.title', event); + + this.reservationForm = this.formBuilder.group({ + reservation: this.formBuilder.array(this.createItems(itemsByCat.ticketCategories)), + additionalService: this.formBuilder.array([]), + captcha: null, + promoCode: null + }); + + this.promoCodeForm = this.formBuilder.group({ + promoCode: this.formBuilder.control(code) + }); + + this.applyItemsByCat(itemsByCat); + this.analytics.pageView(event.analyticsConfiguration); + + if (code) { + this.internalApplyPromoCode(code, err => this.globalErrors = err); + } + }); + }); + } + + private applyItemsByCat(itemsByCat: ItemsByCategory) { + this.ticketCategories = itemsByCat.ticketCategories; + this.expiredCategories = itemsByCat.expiredCategories || []; + + this.ticketCategoryAmount = {}; + this.ticketCategories.forEach(tc => { + this.ticketCategoryAmount[tc.id] = []; + for (let i = 0; i <= tc.maximumSaleableTickets; i++) { + this.ticketCategoryAmount[tc.id].push(i); + } + }); + + this.supplementCategories = itemsByCat.additionalServices.filter(e => e.type === 'SUPPLEMENT'); + this.donationCategories = itemsByCat.additionalServices.filter(e => e.type === 'DONATION'); + + this.preSales = itemsByCat.preSales; + this.waitingList = itemsByCat.waitingList; + this.ticketCategoriesForWaitingList = itemsByCat.ticketCategoriesForWaitingList; + + this.createWaitingListFormIfNecessary(); + } + + private createWaitingListFormIfNecessary() { + if (this.waitingList && !this.waitingListForm) { + this.waitingListForm = this.formBuilder.group({ + firstName: null, + lastName: null, + email: null, + selectedCategory: null, + userLanguage: null, + termAndConditionsAccepted: null, + privacyPolicyAccepted: null + }); + } + } + + private createItems(ticketCategories: TicketCategory[]): UntypedFormGroup[] { + return ticketCategories.map(category => this.formBuilder.group({ticketCategoryId: category.id, amount: 0})); + } + + submitForm(eventShortName: string, reservation: ReservationRequest) { + const request = reservation; + if (reservation.additionalService != null && reservation.additionalService.length > 0) { + request.additionalService = reservation.additionalService.filter(as => (as.amount != null && as.amount > 0) || (as.quantity != null && as.quantity > 0)); + } + this.reservationService.reserveTickets(eventShortName, request, this.translate.currentLang).subscribe(res => { + if (res.success) { + this.router.navigate(['event', eventShortName, 'reservation', res.value, 'book'], { + queryParams: SearchParams.transformParams(this.route.snapshot.queryParams, this.route.snapshot.params) + }); + } + }, (err) => { + this.globalErrors = handleServerSideValidationError(err, this.reservationForm); + this.scrollToTickets(); + }); + } + + private scrollToTickets(): void { + setTimeout(() => { + if (this.tickets != null && this.tickets.nativeElement != null) { + this.tickets.nativeElement.scrollIntoView(true); + } + }, 10); + } + + submitWaitingListRequest(eventShortName: string, waitingListSubscriptionRequest: WaitingListSubscriptionRequest) { + + this.eventService.submitWaitingListSubscriptionRequest(eventShortName, waitingListSubscriptionRequest).subscribe(res => { + this.waitingListRequestSubmitted = true; + this.waitingListRequestResult = res.value; + }, (err) => { + this.globalErrors = handleServerSideValidationError(err, this.waitingListForm); + }); + } + + handleRecaptchaResponse(recaptchaValue: string): void { + this.reservationForm.get('captcha').setValue(recaptchaValue); + } + + private internalApplyPromoCode(promoCode: string, errorHandler: ((errors: ErrorDescriptor[]) => void)): void { + this.globalErrors = []; + this.eventCodeError = false; + + if (promoCode === null || promoCode === undefined || promoCode.trim() === '') { + return; + } + + this.eventService.validateCode(this.event.shortName, promoCode).subscribe(res => { + if (res.success) { + // this.router.navigate([], {relativeTo: this.route, queryParams: {code: promoCode}, queryParamsHandling: "merge"}) + // TODO, set promo code in url, fetch ticket category, rebuild the reservationForm.reservation + + // + this.reloadTicketsInfo(promoCode, res.value); + this.displayPromoCodeForm = false; + // + } else { + this.eventCode = null; // should never enter here + this.reservationForm.get('promoCode').setValue(null); + } + }, (err) => { + errorHandler(handleServerSideValidationError(err, this.promoCodeForm)); + this.eventCode = null; + this.reloadTicketsInfo(null, null); + this.eventCodeError = true; + }); + } + + applyPromoCode(): void { + const promoCode = this.promoCodeForm.get('promoCode').value; + this.globalErrors = []; + this.internalApplyPromoCode(promoCode, () => {}); + } + + removePromoCode(): void { + this.reloadTicketsInfo(null, null); + } + + togglePromoCodeVisible(): void { + this.displayPromoCodeForm = !this.displayPromoCodeForm; + if (this.displayPromoCodeForm) { + setTimeout(() => this.promoCodeElement.nativeElement.focus(), 200); + } else { + this.promoCodeForm.get('promoCode').setValue(null); + } + } + + ticketsLeftCountVisible(): boolean { + return this.event.availableTicketsCount != null + && this.event.availableTicketsCount > 0 + && this.ticketCategories.every(tc => !tc.bounded); + } + + reservationFormItem(parent: UntypedFormGroup, counter: number): UntypedFormGroup { + return (parent.get('reservation') as UntypedFormArray).at(counter) as UntypedFormGroup; + } + + ticketsLeftCountVisibleForCategory(category: TicketCategory): boolean { + return category.availableTickets != null && category.availableTickets > 0; + } + + private reloadTicketsInfo(promoCode: string, eventCode: EventCode) { + this.eventService.getEventTicketsInfo(this.event.shortName, promoCode).subscribe(itemsByCat => { + this.reservationForm.get('promoCode').setValue(promoCode); + this.reservationForm.setControl('reservation', this.formBuilder.array(this.createItems(itemsByCat.ticketCategories))); + this.applyItemsByCat(itemsByCat); + this.eventCode = eventCode; + if (eventCode != null) { + this.scrollToTickets(); + } + }); + } + + promoCodeOnEnter(ev: Event) { + ev.preventDefault(); + if (this.promoCodeForm.invalid) { + return; + } + this.applyPromoCode(); + } + + selectionChange(): void { + if (this.eventCode == null || this.eventCode.type === 'ACCESS') { + this.reservationService.checkDynamicDiscountAvailability(this.event.shortName, this.reservationForm.value) + .subscribe(d => { + this.dynamicDiscount = d; + }); + } + } + + get dynamicDiscountMessage(): string { + if (this.dynamicDiscount != null) { + return this.dynamicDiscount.formattedMessage[this.translate.currentLang]; + } + return null; + } + + get isEventOnline(): boolean { + return this.event.format === 'ONLINE'; + } + + public displayOnlineTicketTag(category: TicketCategory): boolean { + return this.event.format === 'HYBRID' && category.ticketAccessType === 'ONLINE'; + } + + get displayMap(): boolean { + return (this.event.mapUrl && this.event.mapUrl.length > 0) && !this.isEventOnline; + } + +} diff --git a/frontend/projects/public/src/app/event-footer-links/footer-links.component.html b/frontend/projects/public/src/app/event-footer-links/footer-links.component.html new file mode 100644 index 0000000000..f1baca0b7d --- /dev/null +++ b/frontend/projects/public/src/app/event-footer-links/footer-links.component.html @@ -0,0 +1,9 @@ + diff --git a/frontend/projects/public/src/app/event-footer-links/footer-links.component.ts b/frontend/projects/public/src/app/event-footer-links/footer-links.component.ts new file mode 100644 index 0000000000..7df000f97c --- /dev/null +++ b/frontend/projects/public/src/app/event-footer-links/footer-links.component.ts @@ -0,0 +1,14 @@ +import {Component, Input} from '@angular/core'; +import {TermsPrivacyLinksContainer} from '../model/event'; + +@Component({ + selector: 'app-footer-links', + templateUrl: './footer-links.component.html' +}) +export class FooterLinksComponent { + @Input() + marginClass = 'mb-5'; + + @Input() + linksContainer?: TermsPrivacyLinksContainer; +} diff --git a/frontend/projects/public/src/app/event-list-all/event-list-all.component.html b/frontend/projects/public/src/app/event-list-all/event-list-all.component.html new file mode 100644 index 0000000000..dccdde1f7f --- /dev/null +++ b/frontend/projects/public/src/app/event-list-all/event-list-all.component.html @@ -0,0 +1,18 @@ +
+
+ + +

+ +
+ +
+ +
+

+
+ +
+ +
+
diff --git a/frontend/projects/public/src/app/event-list-all/event-list-all.component.scss b/frontend/projects/public/src/app/event-list-all/event-list-all.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/public/src/app/event-list-all/event-list-all.component.ts b/frontend/projects/public/src/app/event-list-all/event-list-all.component.ts new file mode 100644 index 0000000000..cca630d8a6 --- /dev/null +++ b/frontend/projects/public/src/app/event-list-all/event-list-all.component.ts @@ -0,0 +1,57 @@ +import {Component, OnInit} from '@angular/core'; +import {BasicEventInfo} from '../model/basic-event-info'; +import {Language, TermsPrivacyLinksContainer} from '../model/event'; +import {EventService} from '../shared/event.service'; +import {I18nService} from '../shared/i18n.service'; +import {ActivatedRoute, Params, Router} from '@angular/router'; +import {InfoService} from '../shared/info.service'; +import {AnalyticsService} from '../shared/analytics.service'; +import {TranslateService} from '@ngx-translate/core'; +import {of, zip} from 'rxjs'; +import {mergeMap} from 'rxjs/operators'; +import {SearchParams} from '../model/search-params'; +import {globalTermsPrivacyLinks} from '../model/info'; +import {filterAvailableLanguages} from '../model/purchase-context'; + +@Component({ + selector: 'app-event-list-all', + templateUrl: './event-list-all.component.html', + styleUrls: ['./event-list-all.component.scss'] +}) +export class EventListAllComponent implements OnInit { + + events: BasicEventInfo[]; + languages: Language[]; + queryParams: Params; + linksContainer: TermsPrivacyLinksContainer; + + constructor( + private eventService: EventService, + private i18nService: I18nService, + private router: Router, + public translate: TranslateService, + private info: InfoService, + private analytics: AnalyticsService, + private route: ActivatedRoute) { } + + public ngOnInit(): void { + + zip(this.route.queryParams, this.route.params).pipe( + mergeMap(([params, pathParams]) => { + const searchParams = SearchParams.fromQueryAndPathParams(params, pathParams); + return zip(this.eventService.getEvents(searchParams), this.info.getInfo(), of(searchParams), this.i18nService.getAvailableLanguages()); + }) + ).subscribe(([res, info, searchParams, activeLanguages]) => { + this.queryParams = searchParams.toParams(); + if (res.length === 1) { + this.router.navigate(['/event', res[0].shortName], {replaceUrl: true, queryParams: this.queryParams}); + } else { + this.events = res; + this.analytics.pageView(info.analyticsConfiguration); + this.linksContainer = globalTermsPrivacyLinks(info); + this.languages = filterAvailableLanguages(activeLanguages, res); + this.i18nService.setPageTitle('event-list.header.title', null); + } + }); + } +} diff --git a/frontend/projects/public/src/app/event-summary/event-summary.component.html b/frontend/projects/public/src/app/event-summary/event-summary.component.html new file mode 100644 index 0000000000..4e11fad1f9 --- /dev/null +++ b/frontend/projects/public/src/app/event-summary/event-summary.component.html @@ -0,0 +1,25 @@ +
+

+ +
+
+
+
{{'show-event.by'|translate}} {{event.organizationName}}
+
+
+ +
+
+
+ {{'show-event.add-to-calendar' | translate}}   + Google +  –  + iCalendar +
+
+
{{ event.location }}
+
{{'event.online.badge' | translate}}
+ +
+
+
diff --git a/frontend/projects/public/src/app/event-summary/event-summary.component.ts b/frontend/projects/public/src/app/event-summary/event-summary.component.ts new file mode 100644 index 0000000000..96d2ccf002 --- /dev/null +++ b/frontend/projects/public/src/app/event-summary/event-summary.component.ts @@ -0,0 +1,24 @@ +import {Component, Input} from '@angular/core'; +import {Event} from '../model/event'; +import {TranslateService} from '@ngx-translate/core'; +import {DateValidity} from '../model/date-validity'; + +@Component({ + selector: 'app-event-summary', + templateUrl: './event-summary.component.html' +}) +export class EventSummaryComponent { + + @Input() + event: Event; + + @Input() + dateValidityProvider: DateValidity; + + constructor(public translate: TranslateService) { } + + get isEventOnline(): boolean { + return this.event.format === 'ONLINE'; + } + +} diff --git a/frontend/projects/public/src/app/event.guard.ts b/frontend/projects/public/src/app/event.guard.ts new file mode 100644 index 0000000000..f854007cc5 --- /dev/null +++ b/frontend/projects/public/src/app/event.guard.ts @@ -0,0 +1,25 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router'; +import {Observable, of} from 'rxjs'; +import {EventService} from './shared/event.service'; +import {catchError, map, tap} from 'rxjs/operators'; +import {handleCustomCss} from './shared/custom-css-helper'; + +@Injectable({ + providedIn: 'root' +}) +export class EventGuard implements CanActivate { + + constructor(private eventService: EventService, private router: Router) { + } + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const eventShortName = next.params['eventShortName']; + return this.eventService.getEvent(eventShortName) + .pipe( + tap((e) => handleCustomCss(e)), + catchError(e => of(this.router.parseUrl(''))), + map(e => e instanceof UrlTree ? e : true) + ); + } +} diff --git a/frontend/projects/public/src/app/home/home.component.html b/frontend/projects/public/src/app/home/home.component.html new file mode 100644 index 0000000000..1411f55eb8 --- /dev/null +++ b/frontend/projects/public/src/app/home/home.component.html @@ -0,0 +1,42 @@ +
+
+ + +
+

+ +
+
+ +
+
+
+ +
+ + +
+
+
+
+ +
+ +
+

+ +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
diff --git a/frontend/projects/public/src/app/home/home.component.scss b/frontend/projects/public/src/app/home/home.component.scss new file mode 100644 index 0000000000..71e58d1480 --- /dev/null +++ b/frontend/projects/public/src/app/home/home.component.scss @@ -0,0 +1,3 @@ +.card-light:hover { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} diff --git a/frontend/projects/public/src/app/home/home.component.ts b/frontend/projects/public/src/app/home/home.component.ts new file mode 100644 index 0000000000..e329682b91 --- /dev/null +++ b/frontend/projects/public/src/app/home/home.component.ts @@ -0,0 +1,101 @@ +import {Component, OnInit} from '@angular/core'; +import {EventService} from '../shared/event.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {BasicEventInfo} from '../model/basic-event-info'; +import {I18nService} from '../shared/i18n.service'; +import {Language, TermsPrivacyLinksContainer} from '../model/event'; +import {TranslateService} from '@ngx-translate/core'; +import {AnalyticsService} from '../shared/analytics.service'; +import {InfoService} from '../shared/info.service'; +import {zip} from 'rxjs'; +import {SubscriptionService} from '../shared/subscription.service'; +import {BasicSubscriptionInfo} from '../model/subscription'; +import {mergeMap} from 'rxjs/operators'; +import {SearchParams} from '../model/search-params'; +import {globalTermsPrivacyLinks} from '../model/info'; +import {filterAvailableLanguages} from '../model/purchase-context'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.scss'] +}) +export class HomeComponent implements OnInit { + + events: BasicEventInfo[]; + allEvents: BasicEventInfo[]; + subscriptions: BasicSubscriptionInfo[]; + allSubscriptions: BasicSubscriptionInfo[]; + languages: Language[]; + linksContainer: TermsPrivacyLinksContainer; + private searchParams?: SearchParams; + + constructor( + private eventService: EventService, + private subscriptionService: SubscriptionService, + private i18nService: I18nService, + private router: Router, + public translate: TranslateService, + private info: InfoService, + private analytics: AnalyticsService, + private route: ActivatedRoute) { } + + public ngOnInit(): void { + zip(this.route.params, this.route.queryParams).pipe( + mergeMap(([pathParams, queryParams]) => { + this.searchParams = SearchParams.fromQueryAndPathParams(queryParams, pathParams); + return zip( + this.eventService.getEvents(this.searchParams), + this.subscriptionService.getSubscriptions(this.searchParams), + this.info.getInfo(), + this.i18nService.getAvailableLanguages()); + }) + ).subscribe(([res, subscriptions, info, activeLanguages]) => { + if (res.length === 1 && subscriptions.length === 0) { + this.router.navigate(['/event', res[0].shortName], {replaceUrl: true}); + } else { + this.allEvents = res; + this.events = res.slice(0, 4); + this.allSubscriptions = subscriptions; + this.subscriptions = subscriptions.slice(0, 4); + this.analytics.pageView(info.analyticsConfiguration); + this.linksContainer = globalTermsPrivacyLinks(info); + const allPurchaseContexts = [...res, ...subscriptions]; + this.languages = filterAvailableLanguages(activeLanguages, allPurchaseContexts); + } + }); + + this.i18nService.setPageTitle('event-list.header.title', null); + } + + get containsEvents(): boolean { + return this.events != null && this.events.length > 0; + } + + get displayViewAllEventsButton() { + return this.allEvents.length > 4; + } + + get containsSubscriptions(): boolean { + return this.subscriptions != null && this.subscriptions.length > 0; + } + + get displayViewAllSubscriptionsButton() { + return this.allSubscriptions.length > 4; + } + + get allEventsPath(): Array { + if (this.searchParams?.organizerSlug != null) { + return ['/o', this.searchParams.organizerSlug, 'events-all']; + } + return ['events-all']; + } + + get allSubscriptionsPath(): Array { + if (this.searchParams?.organizerSlug != null) { + return ['/o', this.searchParams.organizerSlug, 'subscriptions-all']; + } + return ['subscriptions-all']; + } + +} diff --git a/frontend/projects/public/src/app/item-card/item-card.component.ts b/frontend/projects/public/src/app/item-card/item-card.component.ts new file mode 100644 index 0000000000..8b417f7599 --- /dev/null +++ b/frontend/projects/public/src/app/item-card/item-card.component.ts @@ -0,0 +1,27 @@ +import {Component, Input} from '@angular/core'; +import {UntypedFormGroup} from '@angular/forms'; +import {TicketCategory} from '../model/ticket-category'; +import {AdditionalService} from '../model/additional-service'; +import {BasicEventInfo} from '../model/basic-event-info'; + +@Component({ + selector: 'app-item-card', + templateUrl: './item-card.html', + styleUrls: ['./item-card.scss'] +}) +export class ItemCardComponent { + @Input() + parentFormGroup: UntypedFormGroup; + + @Input() + item: TicketCategory | AdditionalService; + + @Input() + event: BasicEventInfo; + + @Input() + additionalClass = ''; + + @Input() + currentLang: string; +} diff --git a/frontend/projects/public/src/app/item-card/item-card.html b/frontend/projects/public/src/app/item-card/item-card.html new file mode 100644 index 0000000000..2d708b642e --- /dev/null +++ b/frontend/projects/public/src/app/item-card/item-card.html @@ -0,0 +1,23 @@ +
+
+
+

+ +

+
+ + +
+
+ +
+
+ +
+
+
+
+
+
+
+
diff --git a/frontend/projects/public/src/app/item-card/item-card.scss b/frontend/projects/public/src/app/item-card/item-card.scss new file mode 100644 index 0000000000..ab8f8824d4 --- /dev/null +++ b/frontend/projects/public/src/app/item-card/item-card.scss @@ -0,0 +1,48 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/variables"; + + +.item-content-except-desc { + display: flex; + flex-wrap: wrap; +} + +@include media-breakpoint-up(md) { + + /* desktop here */ + .card-title { + order: 0; + max-width: 65%; + } + + .card-sale-period { + order: 3; + flex-basis: 100%; + } + + .card-item-price { + order: 1; + padding-right: 3rem!important; + margin-left: auto; + display: flex; + align-items: center; + } + + .card-qty-container { + order: 2; + @include make-col(2); + } +} + +@include media-breakpoint-down(sm) { + + /* mobile here */ + .item-content-except-desc { + flex-direction: column; + } + + .card-qty-container { + margin-top: 1rem; + } +} diff --git a/frontend/projects/public/src/app/language.guard.ts b/frontend/projects/public/src/app/language.guard.ts new file mode 100644 index 0000000000..aa8064baee --- /dev/null +++ b/frontend/projects/public/src/app/language.guard.ts @@ -0,0 +1,57 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot} from '@angular/router'; +import {Observable} from 'rxjs'; +import {I18nService} from './shared/i18n.service'; +import {TranslateService} from '@ngx-translate/core'; +import {catchError, map, switchMap} from 'rxjs/operators'; +import {PurchaseContextService, PurchaseContextType} from './shared/purchase-context.service'; + +@Injectable({ + providedIn: 'root' +}) +export class LanguageGuard implements CanActivate { + + constructor(private i18nService: I18nService, private purchaseContextService: PurchaseContextService, private translate: TranslateService) { + } + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + + const langQueryParam = next.queryParams['lang']; + const persisted = this.i18nService.getPersistedLanguage(); + + const type: PurchaseContextType = next.data.type; + const publicIdentifier = next.params[next.data.publicIdentifierParameter]; + const req = type && publicIdentifier ? this.getForContext(type, publicIdentifier) : this.getForApp(); + + return req.pipe(switchMap(availableLanguages => { + const lang = this.extractLang(availableLanguages, persisted, langQueryParam); + return this.i18nService.useTranslation(type, publicIdentifier, lang); + })); + } + + private getForContext(type: PurchaseContextType, publicIdentifier: string): Observable { + return this.purchaseContextService.getContext(type, publicIdentifier).pipe(map(p => p.contentLanguages.map(v => v.locale))).pipe(catchError(val => this.getForApp())); + } + + private getForApp(): Observable { + return this.i18nService.getAvailableLanguages().pipe(map(languages => languages.map(l => l.locale))); + } + + private extractLang(availableLanguages: string[], persisted: string, override: string): string { + let lang: string; + if (override && availableLanguages.indexOf(override) >= 0) { + lang = override; + } else if (availableLanguages.indexOf(persisted) >= 0) { + lang = persisted; + } else if (availableLanguages.indexOf(this.translate.getBrowserLang()) >= 0) { + lang = this.translate.getBrowserLang(); + } else if (availableLanguages.indexOf('en') >= 0) { + // use english as a default choice if available in case of mismatching browser lang + lang = 'en'; + } else { + lang = availableLanguages[0]; + } + return lang; + } + +} diff --git a/frontend/projects/public/src/app/model/additional-service.ts b/frontend/projects/public/src/app/model/additional-service.ts new file mode 100644 index 0000000000..f4211177e3 --- /dev/null +++ b/frontend/projects/public/src/app/model/additional-service.ts @@ -0,0 +1,31 @@ +export class AdditionalService { + id: number; + type: AdditionalServiceType; + supplementPolicy: SupplementPolicy; + // + fixPrice: boolean; + availableQuantity: number; + maxQtyPerOrder: number; + + // + free: boolean; + formattedFinalPrice: string; + hasDiscount: boolean; + formattedDiscountedPrice: string; + vatApplies: boolean; + vatIncluded: boolean; + vatPercentage: string; + // + + // + expired: boolean; + saleInFuture: boolean; + formattedInception: {[key: string]: string}; + formattedExpiration: {[key: string]: string}; + title: {[key: string]: string}; + description: {[key: string]: string}; +} + +export type AdditionalServiceType = 'DONATION' | 'SUPPLEMENT'; +export type SupplementPolicy = 'MANDATORY_ONE_FOR_TICKET' | 'OPTIONAL_UNLIMITED_AMOUNT' | 'OPTIONAL_MAX_AMOUNT_PER_TICKET' | + 'OPTIONAL_MAX_AMOUNT_PER_RESERVATION'; diff --git a/frontend/projects/public/src/app/model/analytics-configuration.ts b/frontend/projects/public/src/app/model/analytics-configuration.ts new file mode 100644 index 0000000000..c477f1c818 --- /dev/null +++ b/frontend/projects/public/src/app/model/analytics-configuration.ts @@ -0,0 +1,5 @@ +export class AnalyticsConfiguration { + googleAnalyticsKey: string | null; + googleAnalyticsScrambledInfo: boolean; + clientId: string | null; +} diff --git a/frontend/projects/public/src/app/model/basic-event-info.ts b/frontend/projects/public/src/app/model/basic-event-info.ts new file mode 100644 index 0000000000..86826c49fd --- /dev/null +++ b/frontend/projects/public/src/app/model/basic-event-info.ts @@ -0,0 +1,22 @@ +import {DatesWithOffset, DateValidity} from './date-validity'; +import {EventFormat, Language} from './event'; +import {Localized} from './purchase-context'; + +export class BasicEventInfo implements DateValidity, Localized { + shortName: string; + fileBlobId: string; + format: EventFormat; + title: {[key: string]: string}; + location: string; + + // date related + timeZone: string; + sameDay: boolean; + datesWithOffset: DatesWithOffset; + formattedBeginDate: {[key: string]: string}; // day, month, year + formattedBeginTime: {[key: string]: string}; // the hour/minute component + formattedEndDate: {[key: string]: string}; + formattedEndTime: {[key: string]: string}; + // + contentLanguages: Language[] = []; +} diff --git a/frontend/projects/public/src/app/model/date-validity.ts b/frontend/projects/public/src/app/model/date-validity.ts new file mode 100644 index 0000000000..d06ef22612 --- /dev/null +++ b/frontend/projects/public/src/app/model/date-validity.ts @@ -0,0 +1,16 @@ +export interface DateValidity { + timeZone: string; + sameDay: boolean; + datesWithOffset: DatesWithOffset; + formattedBeginDate: {[key: string]: string}; // day, month, year + formattedBeginTime: {[key: string]: string}; // the hour/minute component + formattedEndDate: {[key: string]: string}; + formattedEndTime: {[key: string]: string}; +} + +export interface DatesWithOffset { + startDateTime: number; + startTimeZoneOffset: number; + endDateTime: number; + endTimeZoneOffset: number; +} diff --git a/frontend/projects/public/src/app/model/embedding-configuration.ts b/frontend/projects/public/src/app/model/embedding-configuration.ts new file mode 100644 index 0000000000..6289937f2f --- /dev/null +++ b/frontend/projects/public/src/app/model/embedding-configuration.ts @@ -0,0 +1,10 @@ +import {ReservationStatus} from './reservation-info'; + +export class ReservationStatusChanged { + constructor(public status: ReservationStatus, public id: string, public error?: string) {} +} + +export interface EmbeddingConfiguration { + enabled: boolean; + notificationOrigin: string; +} diff --git a/frontend/projects/public/src/app/model/event-code.ts b/frontend/projects/public/src/app/model/event-code.ts new file mode 100644 index 0000000000..7a506e68ad --- /dev/null +++ b/frontend/projects/public/src/app/model/event-code.ts @@ -0,0 +1,15 @@ +export class EventCode { + code: string; + type: EventCodeType; + discountType: DiscountType; + discountAmount: string; +} + +export type EventCodeType = 'SPECIAL_PRICE' | 'DISCOUNT' | 'ACCESS'; +export type DiscountType = 'FIXED_AMOUNT' | 'FIXED_AMOUNT_RESERVATION' | 'PERCENTAGE' | 'NONE'; + +export interface DynamicDiscount { + discount: string; + discountType: DiscountType; + formattedMessage: {[key: string]: string}; +} diff --git a/frontend/projects/public/src/app/model/event.ts b/frontend/projects/public/src/app/model/event.ts new file mode 100644 index 0000000000..c604c26389 --- /dev/null +++ b/frontend/projects/public/src/app/model/event.ts @@ -0,0 +1,178 @@ +import {DatesWithOffset, DateValidity} from './date-validity'; +import {AnalyticsConfiguration} from './analytics-configuration'; +import {IconName, IconPrefix} from '@fortawesome/fontawesome-svg-core'; +import {OfflinePaymentConfiguration, PurchaseContext} from './purchase-context'; +import {EmbeddingConfiguration} from './embedding-configuration'; + +export interface TermsPrivacyLinksContainer { + privacyPolicyUrl?: string; + termsAndConditionsUrl?: string; +} + +export class Event implements DateValidity, PurchaseContext { + shortName: string; + title: { [lang: string]: string }; + format: EventFormat; + fileBlobId: string; + contentLanguages: Language[]; + websiteUrl: string; + location: string; + privacyPolicyUrl: string; + termsAndConditionsUrl: string; + mapUrl: string; + + organizationName: string; + organizationEmail: string; + + description: {[key: string]: string}; + vatIncluded: boolean; + vat: string; + free: boolean; + + // + bankAccount: string; + bankAccountOwner: string[]; + // + currency: string; + currencyDescriptor: CurrencyDescriptor; + + // date related + timeZone: string; + datesWithOffset: DatesWithOffset; + sameDay: boolean; + formattedBeginDate: {[key: string]: string}; // day, month, year + formattedBeginTime: {[key: string]: string}; // the hour/minute component + formattedEndDate: {[key: string]: string}; + formattedEndTime: {[key: string]: string}; + // + + // + invoicingConfiguration: InvoicingConfiguration; + // + captchaConfiguration: CaptchaConfiguration; + // + assignmentConfiguration: AssignmentConfiguration; + // + promotionsConfiguration: PromotionsConfiguration; + // + analyticsConfiguration: AnalyticsConfiguration; + + embeddingConfiguration: EmbeddingConfiguration; + + i18nOverride: {[lang: string]: {[key: string]: string}}; + + availableTicketsCount: number | null; + + customCss: string | null; + + canApplySubscriptions: boolean; + + offlinePaymentConfiguration: OfflinePaymentConfiguration = { + showOnlyBasicInstructions: false + }; +} + +export class InvoicingConfiguration { + userCanDownloadReceiptOrInvoice: boolean; + euVatCheckingEnabled: boolean; + invoiceAllowed: boolean; + onlyInvoice: boolean; + customerReferenceEnabled: boolean; + enabledItalyEInvoicing: boolean; + vatNumberStrictlyRequired: boolean; +} + +export class Language { + locale: string; + displayLanguage: string; +} + +export class PaymentProxyWithParameters { + paymentProxy: PaymentProxy; + parameters: {[key: string]: any}; +} + +export type EventFormat = 'IN_PERSON' | 'ONLINE' | 'HYBRID'; + +export type PaymentMethod = 'CREDIT_CARD' | 'PAYPAL' | 'IDEAL' | 'BANK_TRANSFER' | 'ON_SITE' + | 'APPLE_PAY' | 'BANCONTACT' | 'ING_HOME_PAY' | 'BELFIUS' | 'PRZELEWY_24' | 'KBC' | 'NONE'; +export type PaymentProxy = 'STRIPE' | 'ON_SITE' | 'OFFLINE' | 'PAYPAL' | 'MOLLIE' | 'SAFERPAY'; +export interface PaymentMethodDetails { + labelKey: string; + icon: [IconPrefix, IconName]; +} + +export const paymentMethodDetails: {[key in PaymentMethod]: PaymentMethodDetails} = { + 'CREDIT_CARD': { + labelKey: 'reservation-page.credit-card', + icon: ['fas', 'credit-card'] + }, + 'PAYPAL': { + labelKey: 'reservation-page.paypal', + icon: ['fab', 'paypal'] + }, + 'IDEAL': { + labelKey: 'reservation-page.payment-method.ideal', + icon: ['fab', 'ideal'] + }, + 'BANCONTACT': { + labelKey: 'reservation-page.payment-method.bancontact', + icon: ['fas', 'exchange-alt'] + }, + 'ING_HOME_PAY': { + labelKey: 'reservation-page.payment-method.ing-home-pay', + icon: ['fas', 'exchange-alt'] + }, + 'BELFIUS': { + labelKey: 'reservation-page.payment-method.belfius', + icon: ['fas', 'exchange-alt'] + }, + 'PRZELEWY_24': { + labelKey: 'reservation-page.payment-method.przelewy-24', + icon: ['fas', 'exchange-alt'] + }, + 'BANK_TRANSFER': { + labelKey: 'reservation-page.offline', + icon: ['fas', 'exchange-alt'] + }, + 'ON_SITE': { + labelKey: 'reservation-page.on-site', + icon: ['fas', 'money-bill'] + }, + 'APPLE_PAY': { + labelKey: 'reservation-page.payment-method.apple-pay', + icon: ['fab', 'apple-pay'] + }, + 'KBC': { + labelKey: 'reservation-page.payment-method.kbc', + icon: ['fas', 'money-check-alt'] + }, + 'NONE': { + labelKey: null, + icon: ['fas', 'exchange-alt'] + } +}; + +export class CaptchaConfiguration { + captchaForTicketSelection: boolean; + captchaForOfflinePaymentAndFree: boolean; + recaptchaApiKey: string; +} + +export class AssignmentConfiguration { + forceAssignment: boolean; + enableAttendeeAutocomplete: boolean; + enableTicketTransfer: boolean; +} + +export class PromotionsConfiguration { + hasAccessPromotions: boolean; + usePartnerCode: boolean; +} + +export interface CurrencyDescriptor { + code: string; + name: string; + symbol: string; + fractionDigits: number; +} diff --git a/frontend/projects/public/src/app/model/feedback.ts b/frontend/projects/public/src/app/model/feedback.ts new file mode 100644 index 0000000000..0c5c2218dc --- /dev/null +++ b/frontend/projects/public/src/app/model/feedback.ts @@ -0,0 +1,7 @@ +export type FeedbackType = 'SUCCESS' | 'ERROR' | 'INFO'; + +export interface FeedbackContent { + type?: FeedbackType; + active: boolean; + message?: string; +} diff --git a/frontend/projects/public/src/app/model/info.ts b/frontend/projects/public/src/app/model/info.ts new file mode 100644 index 0000000000..f328c2ab14 --- /dev/null +++ b/frontend/projects/public/src/app/model/info.ts @@ -0,0 +1,23 @@ +import {AnalyticsConfiguration} from './analytics-configuration'; +import {InvoicingConfiguration, TermsPrivacyLinksContainer} from './event'; + +export interface Info { + demoModeEnabled: boolean; + devModeEnabled: boolean; + prodModeEnabled: boolean; + analyticsConfiguration: AnalyticsConfiguration; + globalPrivacyPolicyUrl?: string; + globalTermsUrl?: string; + invoicingConfiguration?: InvoicingConfiguration; + announcementBannerContentHTML?: string; + walletConfiguration: WalletConfiguration; +} + +export interface WalletConfiguration { + gWalletEnabled: boolean; + passEnabled: boolean; +} + +export function globalTermsPrivacyLinks(info: Info): TermsPrivacyLinksContainer { + return { privacyPolicyUrl: info.globalPrivacyPolicyUrl, termsAndConditionsUrl: info.globalTermsUrl }; +} diff --git a/frontend/projects/public/src/app/model/items-by-category.ts b/frontend/projects/public/src/app/model/items-by-category.ts new file mode 100644 index 0000000000..4fb9da59d4 --- /dev/null +++ b/frontend/projects/public/src/app/model/items-by-category.ts @@ -0,0 +1,18 @@ +import {TicketCategory} from './ticket-category'; +import {AdditionalService} from './additional-service'; + +export class ItemsByCategory { + + ticketCategories: TicketCategory[]; + expiredCategories: TicketCategory[]; + additionalServices: AdditionalService[]; + + waitingList: boolean; + preSales: boolean; + ticketCategoriesForWaitingList: TicketCategoryForWaitingList[]; +} + +export class TicketCategoryForWaitingList { + id: number; + name: string; +} diff --git a/frontend/projects/public/src/app/model/localized-country.ts b/frontend/projects/public/src/app/model/localized-country.ts new file mode 100644 index 0000000000..5e63604081 --- /dev/null +++ b/frontend/projects/public/src/app/model/localized-country.ts @@ -0,0 +1,4 @@ +export class LocalizedCountry { + isoCode: string; + name: string; +} diff --git a/frontend/projects/public/src/app/model/overview-confirmation.ts b/frontend/projects/public/src/app/model/overview-confirmation.ts new file mode 100644 index 0000000000..5b71806488 --- /dev/null +++ b/frontend/projects/public/src/app/model/overview-confirmation.ts @@ -0,0 +1,4 @@ +export class OverviewConfirmation { + termAndConditionsAccepted: boolean; + privacyPolicyAccepted: boolean; +} diff --git a/frontend/projects/public/src/app/model/payment.ts b/frontend/projects/public/src/app/model/payment.ts new file mode 100644 index 0000000000..af82cb6a9c --- /dev/null +++ b/frontend/projects/public/src/app/model/payment.ts @@ -0,0 +1,4 @@ +export class TransactionInitializationToken { + clientSecret: string; + reservationStatusChanged: boolean; +} diff --git a/frontend/projects/public/src/app/model/purchase-context.ts b/frontend/projects/public/src/app/model/purchase-context.ts new file mode 100644 index 0000000000..d8a22b57b0 --- /dev/null +++ b/frontend/projects/public/src/app/model/purchase-context.ts @@ -0,0 +1,60 @@ +import {AnalyticsConfiguration} from './analytics-configuration'; +import {AssignmentConfiguration, CaptchaConfiguration, CurrencyDescriptor, InvoicingConfiguration, Language, TermsPrivacyLinksContainer} from './event'; +import {EmbeddingConfiguration} from './embedding-configuration'; + +export interface Localized { + contentLanguages: Language[]; +} + +export function filterAvailableLanguages(activeLanguages: Language[], purchaseContexts: Localized[]): Language[] { + if (purchaseContexts.length > 0) { + const languagesFromPc = purchaseContexts.map(pc => pc.contentLanguages.map(l => l.locale)).reduce((accumulator, current) => { + if (accumulator.length === 0) { + accumulator.push(...current); + return accumulator; + } else { + return accumulator.filter(l => current.some(l1 => l1 === l)); + } + }, []); + const filtered = activeLanguages.filter(al => languagesFromPc.some(l => l === al.locale)); + if (filtered.length > 0) { + return filtered; + } + } + return activeLanguages; +} + +export interface PurchaseContext extends PurchaseContextPriceDescriptor, Localized, TermsPrivacyLinksContainer { + title: { [lang: string]: string }; + invoicingConfiguration: InvoicingConfiguration; + assignmentConfiguration: AssignmentConfiguration; + analyticsConfiguration: AnalyticsConfiguration; + captchaConfiguration: CaptchaConfiguration; + offlinePaymentConfiguration: OfflinePaymentConfiguration; + + embeddingConfiguration: EmbeddingConfiguration; + + fileBlobId: string; + + bankAccount: string; + bankAccountOwner: string[]; + + organizationEmail: string; + + // + websiteUrl: string; + shortName: string; + + canApplySubscriptions: boolean; +} + +export interface PurchaseContextPriceDescriptor { + currencyDescriptor: CurrencyDescriptor; + vat: string; + currency: string; + vatIncluded: boolean; +} + +export interface OfflinePaymentConfiguration { + showOnlyBasicInstructions: boolean; +} diff --git a/frontend/projects/public/src/app/model/reservation-info.ts b/frontend/projects/public/src/app/model/reservation-info.ts new file mode 100644 index 0000000000..cc56332d96 --- /dev/null +++ b/frontend/projects/public/src/app/model/reservation-info.ts @@ -0,0 +1,146 @@ +import {Ticket} from './ticket'; +import {PaymentMethod, PaymentProxy, PaymentProxyWithParameters} from './event'; +import {TicketAccessType} from './ticket-category'; + +export class ReservationInfo { + id: string; + shortId: string; + firstName: string; + lastName: string; + email: string; + validity: number; + ticketsByCategory: TicketsByTicketCategory[]; + orderSummary: OrderSummary; + + // + status: ReservationStatus; + validatedBookingInformation: boolean; + // + formattedExpirationDate: {[key: string]: string}; + // + + // + invoiceNumber: string; + invoiceRequested: boolean; + invoiceOrReceiptDocumentPresent: boolean; + paid: boolean; + // + tokenAcquired: boolean; + paymentProxy: PaymentProxy; + // + addCompanyBillingDetails: boolean; + customerReference: string; + skipVatNr: boolean; + + billingAddress: string; + // + billingDetails: BillingDetails; + + // group related info + containsCategoriesLinkedToGroups: boolean; + // + + activePaymentMethods: {[key in PaymentMethod]?: PaymentProxyWithParameters}; + subscriptionInfos?: Array; + metadata: ReservationMetadata; +} + +export interface ReservationMetadata { + hideContactData: boolean; + lockEmailEdit: boolean; + hideConfirmationButtons: boolean; + readyForConfirmation: boolean; + finalized: boolean; +} + +export class ReservationSubscriptionInfo { + id?: string; + pin?: string; + usageDetails?: SubscriptionUsageDetails; + owner?: SubscriptionOwner; + configuration?: SubscriptionConfiguration; +} + +export class SubscriptionOwner { + firstName: string; + lastName: string; + email: string; +} + +export interface SubscriptionConfiguration { + displayPin: boolean; +} + +export interface SubscriptionUsageDetails { + total: number | null; + used: number; + available: number | null; +} + +export class ReservationStatusInfo { + status: ReservationStatus; + validatedBookingInformation: boolean; +} + +export class TicketsByTicketCategory { + name: string; + ticketAccessType: TicketAccessType; + tickets: Ticket[]; +} + +export type SummaryType = 'TICKET' | 'PROMOTION_CODE' | 'DYNAMIC_DISCOUNT' | 'ADDITIONAL_SERVICE' | 'APPLIED_SUBSCRIPTION' | 'TAX_DETAIL'; + +export class OrderSummary { + summary: SummaryRow[]; + totalPrice: string; + free: boolean; + displayVat: boolean; + priceInCents: number; + descriptionForPayment: string; + totalVAT: string; + vatPercentage: string; +} + +export class SummaryRow { + name: string; + amount: number; + price: string; + subTotal: string; + type: SummaryType; + taxPercentage: string; +} + +export type ReservationStatus = 'PENDING' | 'IN_PAYMENT' | 'EXTERNAL_PROCESSING_PAYMENT' | + 'WAITING_EXTERNAL_CONFIRMATION' | 'OFFLINE_PAYMENT' | 'DEFERRED_OFFLINE_PAYMENT' | + 'OFFLINE_FINALIZING' | 'FINALIZING' | 'COMPLETE' | 'STUCK' | 'CANCELLED' | + 'CREDIT_NOTE_ISSUED' | 'NOT_FOUND'; + +export type ItalianEInvoicingReferenceType = 'ADDRESSEE_CODE' | 'PEC' | 'NONE'; + +export interface BillingDetails { + companyName: string; + addressLine1: string; + addressLine2: string; + zip: string; + city: string; + state: string; + country: string; + taxId: string; + invoicingAdditionalInfo: TicketReservationInvoicingAdditionalInfo; +} + +export interface TicketReservationInvoicingAdditionalInfo { + italianEInvoicing?: ItalianEInvoicing; +} + +export interface ItalianEInvoicing { + referenceType: ItalianEInvoicingReferenceType; + fiscalCode: string; + addresseeCode: string; + pec: string; + /** + * either addressee code, pec, or null + */ + reference: string; + splitPayment: boolean; +} diff --git a/frontend/projects/public/src/app/model/reservation-payment-result.ts b/frontend/projects/public/src/app/model/reservation-payment-result.ts new file mode 100644 index 0000000000..de64ed0519 --- /dev/null +++ b/frontend/projects/public/src/app/model/reservation-payment-result.ts @@ -0,0 +1,7 @@ +export class ReservationPaymentResult { + success: boolean; + failure: boolean; + redirect: boolean; + redirectUrl: string; + gatewayIdOrNull: string; +} diff --git a/frontend/projects/public/src/app/model/reservation-request.ts b/frontend/projects/public/src/app/model/reservation-request.ts new file mode 100644 index 0000000000..a1df5c591b --- /dev/null +++ b/frontend/projects/public/src/app/model/reservation-request.ts @@ -0,0 +1,17 @@ +export class ReservationRequest { + promoCode: string; + reservation: TicketReservation[]; + additionalService: SelectedAdditionalService[]; + captcha: string; +} + +export class TicketReservation { + ticketCategoryId: number; + amount: number; +} + +export class SelectedAdditionalService { + additionalServiceId: number; + amount: number; + quantity: number; +} diff --git a/frontend/projects/public/src/app/model/search-params.ts b/frontend/projects/public/src/app/model/search-params.ts new file mode 100644 index 0000000000..b648566961 --- /dev/null +++ b/frontend/projects/public/src/app/model/search-params.ts @@ -0,0 +1,46 @@ +import {Params} from '@angular/router'; +import {HttpParams} from '@angular/common/http'; + +export class SearchParams { + public constructor(private subscription: string, + private organizer: string, + public organizerSlug: string, + private tags: Array) { + } + + public static fromQueryAndPathParams(params: Params, pathParams: Params): SearchParams { + return new SearchParams(params.subscription, params.organizer, pathParams.organizerSlug, params.tags); + } + + public static transformParams(params: Params, pathParams: Params): Params { + return SearchParams.fromQueryAndPathParams(params, pathParams).toParams(); + } + + public toHttpParams(): HttpParams { + return new HttpParams({ + fromObject: this.extractParams() + }); + } + + public toParams(): Params { + return this.extractParams(); + } + + private extractParams(): { [param: string]: string | ReadonlyArray } { + const obj: { [param: string]: string | ReadonlyArray } = {}; + if (this.subscription != null) { + obj.subscription = this.subscription; + } + if (this.organizer != null) { + obj.organizer = this.organizer; + } + if (this.tags != null) { + obj.tags = this.tags; + } + if (this.organizerSlug != null) { + obj.organizerSlug = this.organizerSlug; + } + return obj; + } + +} diff --git a/frontend/projects/public/src/app/model/subscription.ts b/frontend/projects/public/src/app/model/subscription.ts new file mode 100644 index 0000000000..ded4232f2f --- /dev/null +++ b/frontend/projects/public/src/app/model/subscription.ts @@ -0,0 +1,106 @@ +import {AnalyticsConfiguration} from './analytics-configuration'; +import {AssignmentConfiguration, CaptchaConfiguration, CurrencyDescriptor, InvoicingConfiguration, Language} from './event'; +import {Localized, OfflinePaymentConfiguration, PurchaseContext, PurchaseContextPriceDescriptor} from './purchase-context'; +import {DatesWithOffset} from './date-validity'; +import {EmbeddingConfiguration} from './embedding-configuration'; + +export interface SubscriptionSummaryData extends PurchaseContextPriceDescriptor, Localized { + salePeriod: DatesWithOffset; + formattedOnSaleFrom: { [key: string]: string }; + formattedOnSaleTo?: { [key: string]: string }; + formattedValidFrom?: { [key: string]: string }; + formattedValidTo?: { [key: string]: string }; + validityType: SubscriptionValidityType; + usageType: SubscriptionUsageType; + timeZone: string; + formattedPrice: string; + validityTimeUnit?: SubscriptionTimeUnit; + validityUnits?: number; + maxEntries?: number; + organizationEmail: string; + organizationName: string; +} + +export class BasicSubscriptionInfo implements SubscriptionSummaryData { + id: string; + fileBlobId: string; + title: { [lang: string]: string }; + description: { [lang: string]: string }; + + salePeriod: DatesWithOffset; + validityType: SubscriptionValidityType; + usageType: SubscriptionUsageType; + timeZone: string; + validityTimeUnit?: SubscriptionTimeUnit; + validityUnits?: number; + maxEntries?: number; + + organizationEmail: string; + organizationName: string; + + formattedPrice: string; + currency: string; + currencyDescriptor: CurrencyDescriptor; + vat: string; + vatIncluded: boolean; + + formattedOnSaleFrom: { [key: string]: string }; + formattedOnSaleTo?: { [key: string]: string }; + contentLanguages: Language[] = []; + +} + +export type SubscriptionValidityType = 'STANDARD' | 'CUSTOM' | 'NOT_SET'; +export type SubscriptionTimeUnit = 'DAYS' | 'MONTHS' | 'YEARS'; +export type SubscriptionUsageType = 'ONCE_PER_EVENT' | 'UNLIMITED'; + +export class SubscriptionInfo implements PurchaseContext, SubscriptionSummaryData { + id: string; + + invoicingConfiguration: InvoicingConfiguration; + assignmentConfiguration: AssignmentConfiguration; + analyticsConfiguration: AnalyticsConfiguration; + captchaConfiguration: CaptchaConfiguration; + embeddingConfiguration: EmbeddingConfiguration; + contentLanguages: Language[] = []; + termsAndConditionsUrl: string; + privacyPolicyUrl: string; + fileBlobId: string; + vat: string; + currencyDescriptor: CurrencyDescriptor; + currency: string; + vatIncluded: boolean; + title: { [lang: string]: string }; + description: { [lang: string]: string }; + formattedPrice: string; + numAvailable: number; + + // + bankAccount: string; + bankAccountOwner: string[]; + // + organizationEmail: string; + organizationName: string; + + canApplySubscriptions: boolean; + + // FIXME / CHECK: + websiteUrl: string; + shortName: string; + + salePeriod: DatesWithOffset; + formattedOnSaleFrom: { [key: string]: string }; + formattedOnSaleTo?: { [key: string]: string }; + timeZone: string; + validityType: SubscriptionValidityType; + usageType: SubscriptionUsageType; + validityTimeUnit?: SubscriptionTimeUnit; + validityUnits?: number; + formattedValidFrom?: { [key: string]: string }; + formattedValidTo?: { [key: string]: string }; + maxEntries?: number; + + offlinePaymentConfiguration: OfflinePaymentConfiguration = { + showOnlyBasicInstructions: false + }; +} diff --git a/frontend/projects/public/src/app/model/ticket-category.ts b/frontend/projects/public/src/app/model/ticket-category.ts new file mode 100644 index 0000000000..93fe47fcae --- /dev/null +++ b/frontend/projects/public/src/app/model/ticket-category.ts @@ -0,0 +1,31 @@ +export type TicketAccessType = 'INHERIT' | 'IN_PERSON' | 'ONLINE'; + +export interface TicketCategory { + id: number; + name: string; + ticketAccessType: TicketAccessType; + bounded: boolean; + maximumSaleableTickets: number; + description: {[key: string]: string}; + free: boolean; + formattedFinalPrice: string; + hasDiscount: boolean; + formattedDiscountedPrice: string; + + + // + expired: boolean; + saleInFuture: boolean; + formattedInception: {[key: string]: string}; + formattedExpiration: {[key: string]: string}; + // + + saleableAndLimitNotReached: boolean; + accessRestricted: boolean; + soldOutOrLimitReached: boolean; + + availableTickets: number | null; + + displayTaxInformation: boolean; +} + diff --git a/frontend/projects/public/src/app/model/ticket-info.ts b/frontend/projects/public/src/app/model/ticket-info.ts new file mode 100644 index 0000000000..b9e24a98da --- /dev/null +++ b/frontend/projects/public/src/app/model/ticket-info.ts @@ -0,0 +1,22 @@ +import {DatesWithOffset, DateValidity} from './date-validity'; + +export class TicketInfo implements DateValidity { + fullName: string; + email: string; + uuid: string; + + ticketCategoryName: string; + reservationFullName: string; + reservationId: string; + + deskPaymentRequired: boolean; + + + timeZone: string; + sameDay: boolean; + datesWithOffset: DatesWithOffset; + formattedBeginDate: {[key: string]: string}; // day, month, year + formattedBeginTime: {[key: string]: string}; // the hour/minute component + formattedEndDate: {[key: string]: string}; + formattedEndTime: {[key: string]: string}; +} diff --git a/frontend/projects/public/src/app/model/ticket.ts b/frontend/projects/public/src/app/model/ticket.ts new file mode 100644 index 0000000000..fbc3d6565f --- /dev/null +++ b/frontend/projects/public/src/app/model/ticket.ts @@ -0,0 +1,44 @@ +export class Ticket { + uuid: string; + firstName: string; + lastName: string; + email: string; + fullName: string; + userLanguage: string; + assigned: boolean; + locked: boolean; + acquired: boolean; + cancellationEnabled: boolean; + sendMailEnabled: boolean; + downloadEnabled: boolean; + ticketFieldConfigurationBeforeStandard: AdditionalField[]; + ticketFieldConfigurationAfterStandard: AdditionalField[]; + formattedOnlineCheckInDate: {[key: string]: string}; + onlineEventStarted: boolean; +} + +export class AdditionalField { + name: string; + value: string; + type: AdditionalFieldType; + required: boolean; + editable: boolean; + minLength: number; + maxLength: number; + restrictedValues: string[]; + fields: Field[]; + description: {[key: string]: Description}; +} + +export class Description { + label: string; + placeholder: string; + restrictedValuesDescription: {[key: string]: string}; +} + +export class Field { + fieldIndex: number; + fieldValue: string; +} + +export type AdditionalFieldType = 'input:text' | 'input:tel' | 'vat:eu' | 'textarea' | 'country' | 'select' | 'checkbox' | 'radio'; diff --git a/frontend/projects/public/src/app/model/user.ts b/frontend/projects/public/src/app/model/user.ts new file mode 100644 index 0000000000..4c5956c151 --- /dev/null +++ b/frontend/projects/public/src/app/model/user.ts @@ -0,0 +1,67 @@ +import {BillingDetails, ReservationStatus} from './reservation-info'; +import {PurchaseContextType} from '../shared/purchase-context.service'; + +export interface AuthenticationStatus { + enabled: boolean; + user?: User; +} + +export interface User { + firstName?: string; + lastName?: string; + emailAddress?: string; + profile?: UserProfile; + external?: boolean; +} + +export interface UserProfile { + billingDetails: BillingDetails; + additionalData: UserAdditionalData; +} + +export interface UserAdditionalData { + [key: string]: AdditionalInfoWithLabel; +} + +export interface AdditionalInfoWithLabel { + label: {[key: string]: string}; + values: string[]; +} + +export const ANONYMOUS: User = {}; + +export interface PurchaseContextWithReservation { + title: { [lang: string]: string }; + publicIdentifier: string; + type: PurchaseContextType; + formattedStartDate?: {[key: string]: string}; + formattedEndDate?: {[key: string]: string}; + sameDay: boolean; + reservations: Array; +} + +export interface ReservationHeader { + id: string; + status: ReservationStatus; + formattedExpiresOn: {[key: string]: string}; + formattedConfirmedOn: {[key: string]: string}; + formattedCreatedOn: {[key: string]: string}; + invoiceNumber: string; + finalPrice: number; + currencyCode: string; + usedVatPercent: string; + vatStatus: string; + items: Array; +} + +export interface ClientRedirect { + targetUrl?: string; + empty: boolean; +} + +export interface PurchaseContextItem { + id: string; + firstName: string; + lastName: string; + type: { [k: string]: string }; +} diff --git a/frontend/projects/public/src/app/model/validated-response.ts b/frontend/projects/public/src/app/model/validated-response.ts new file mode 100644 index 0000000000..04c88d0cdf --- /dev/null +++ b/frontend/projects/public/src/app/model/validated-response.ts @@ -0,0 +1,18 @@ +export class ValidatedResponse { + success: boolean; + errorCount: number; + validationErrors: ErrorDescriptor[]; + value: T; + warnings: Array; +} + +export class ErrorDescriptor { + fieldName: string; + code: string; + arguments: {[key: string]: any}; +} + +export interface WarningMessage { + code: string; + params: Array; +} diff --git a/frontend/projects/public/src/app/model/waiting-list-subscription-request.ts b/frontend/projects/public/src/app/model/waiting-list-subscription-request.ts new file mode 100644 index 0000000000..7fb4e34e7f --- /dev/null +++ b/frontend/projects/public/src/app/model/waiting-list-subscription-request.ts @@ -0,0 +1,9 @@ +export class WaitingListSubscriptionRequest { + firstName: string; + lastName: string; + email: string; + userLanguage: string; + termAndConditionsAccepted: string; + privacyPolicyAccepted: string; + selectedCategory: string; +} diff --git a/frontend/projects/public/src/app/my-orders/my-orders.component.html b/frontend/projects/public/src/app/my-orders/my-orders.component.html new file mode 100644 index 0000000000..3dff2935e1 --- /dev/null +++ b/frontend/projects/public/src/app/my-orders/my-orders.component.html @@ -0,0 +1,51 @@ +
+
+ + + +
+

{{ localizedTitle(order) }} - {{order.formattedStartDate | translateDescription }}

+
+ + + + + + + + + + + + + + + + + + + + +
+ + {{ reservation.id | slice:0:8 | uppercase }} + + {{reservation.formattedConfirmedOn | translateDescription }} +
    +
  • + {{item.firstName}} {{item.lastName}} + ({{item.type | translateDescription}}) +
  • +
+
{{getReservationCost(reservation)}}
+
+
+
+ +
+
diff --git a/frontend/projects/public/src/app/my-orders/my-orders.component.ts b/frontend/projects/public/src/app/my-orders/my-orders.component.ts new file mode 100644 index 0000000000..6ce4d43d4f --- /dev/null +++ b/frontend/projects/public/src/app/my-orders/my-orders.component.ts @@ -0,0 +1,65 @@ +import {Component, OnInit} from '@angular/core'; +import {UserService} from '../shared/user.service'; +import {PurchaseContextWithReservation, ReservationHeader} from '../model/user'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../shared/i18n.service'; +import {Language} from '../model/event'; +import {IconProp} from '@fortawesome/fontawesome-svg-core'; +import {getLocalizedContent} from '../shared/subscription.service'; + +@Component({ + selector: 'app-my-orders', + templateUrl: './my-orders.component.html' +}) +export class MyOrdersComponent implements OnInit { + + orders: Array = []; + languages: Language[]; + + constructor(private userService: UserService, + private translateService: TranslateService, + private i18nService: I18nService) { + } + + ngOnInit(): void { + this.userService.getOrders() + .subscribe(array => this.orders = array); + this.i18nService.getAvailableLanguages().subscribe(res => { + this.languages = res; + }); + this.i18nService.setPageTitle('user.menu.my-orders', null); + } + + localizedTitle(p: PurchaseContextWithReservation): string { + const lang = this.translateService.currentLang; + return getLocalizedContent(p.title, lang); + } + + getStatusIcon(reservation: ReservationHeader): IconProp { + if (reservation.status === 'COMPLETE') { + return ['fas', 'check']; + } + return ['far', 'clock']; + } + + getTextClass(reservation: ReservationHeader): string { + if (reservation.status === 'COMPLETE') { + return 'text-success'; + } + return 'text-warning'; + } + + getStatusDescription(reservation: ReservationHeader): string { + if (reservation.status === 'COMPLETE') { + return 'my-orders.status.complete'; + } + return 'my-orders.status.pending'; + } + + getReservationCost(reservation: ReservationHeader): string { + if (reservation.finalPrice > 0) { + return reservation.currencyCode + ' ' + reservation.finalPrice; + } + return this.translateService.instant('common.free'); + } +} diff --git a/frontend/projects/public/src/app/my-profile/my-profile-delete-warning.component.html b/frontend/projects/public/src/app/my-profile/my-profile-delete-warning.component.html new file mode 100644 index 0000000000..f67f368593 --- /dev/null +++ b/frontend/projects/public/src/app/my-profile/my-profile-delete-warning.component.html @@ -0,0 +1,26 @@ + diff --git a/frontend/projects/public/src/app/my-profile/my-profile-delete-warning.component.ts b/frontend/projects/public/src/app/my-profile/my-profile-delete-warning.component.ts new file mode 100644 index 0000000000..c054c8eecc --- /dev/null +++ b/frontend/projects/public/src/app/my-profile/my-profile-delete-warning.component.ts @@ -0,0 +1,25 @@ +import {Component} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; +import {UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms'; + +@Component({ + selector: 'app-my-profile-delete-warning', + templateUrl: './my-profile-delete-warning.component.html' +}) +export class MyProfileDeleteWarningComponent { + + form: UntypedFormGroup; + + constructor(public activeModal: NgbActiveModal, builder: UntypedFormBuilder) { + this.form = builder.group({ + acknowledge: builder.control(false, Validators.required) + }); + } + + confirm(): void { + if (this.form.valid) { + console.log('closing'); + this.activeModal.close('ok'); + } + } +} diff --git a/frontend/projects/public/src/app/my-profile/my-profile.component.html b/frontend/projects/public/src/app/my-profile/my-profile.component.html new file mode 100644 index 0000000000..f8fd83033e --- /dev/null +++ b/frontend/projects/public/src/app/my-profile/my-profile.component.html @@ -0,0 +1,63 @@ +
+
+
+ + + +
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+ +
+ +
+ +
+ + +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ +
+

{{ 'my-profile.delete-profile' | translate }}

+

{{ 'my-profile.delete-profile.description' | translate }}

+
+
+ +
+
+
+ +
+
+
diff --git a/frontend/projects/public/src/app/my-profile/my-profile.component.scss b/frontend/projects/public/src/app/my-profile/my-profile.component.scss new file mode 100644 index 0000000000..395f754f83 --- /dev/null +++ b/frontend/projects/public/src/app/my-profile/my-profile.component.scss @@ -0,0 +1,3 @@ +.delete-profile { + margin-top: 100px; +} diff --git a/frontend/projects/public/src/app/my-profile/my-profile.component.ts b/frontend/projects/public/src/app/my-profile/my-profile.component.ts new file mode 100644 index 0000000000..ab4247a90a --- /dev/null +++ b/frontend/projects/public/src/app/my-profile/my-profile.component.ts @@ -0,0 +1,131 @@ +import {Component, OnInit} from '@angular/core'; +import {UserService} from '../shared/user.service'; +import {User, UserAdditionalData} from '../model/user'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../shared/i18n.service'; +import {InvoicingConfiguration, Language} from '../model/event'; +import {zip} from 'rxjs'; +import {UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms'; +import {BookingComponent} from '../reservation/booking/booking.component'; +import {handleServerSideValidationError} from '../shared/validation-helper'; +import {ErrorDescriptor} from '../model/validated-response'; +import {InfoService} from '../shared/info.service'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {MyProfileDeleteWarningComponent} from './my-profile-delete-warning.component'; +import {FeedbackService} from '../shared/feedback/feedback.service'; +import {DELETE_ACCOUNT_CONFIRMATION, writeToSessionStorage} from '../shared/util'; + +@Component({ + selector: 'app-my-profile', + templateUrl: './my-profile.component.html', + styleUrls: ['./my-profile.component.scss'] +}) +export class MyProfileComponent implements OnInit { + + user?: User; + languages: Language[]; + userForm?: UntypedFormGroup; + invoicingConfiguration?: InvoicingConfiguration; + globalErrors: ErrorDescriptor[]; + additionalData?: UserAdditionalData; + + constructor(private userService: UserService, + private translateService: TranslateService, + private i18nService: I18nService, + private formBuilder: UntypedFormBuilder, + private infoService: InfoService, + private modalService: NgbModal, + private feedbackService: FeedbackService) { + this.userForm = this.formBuilder.group({ + firstName: this.formBuilder.control(null, Validators.required), + lastName: this.formBuilder.control(null, Validators.required), + addCompanyBillingDetails: this.formBuilder.control(false), + billingAddressCompany: this.formBuilder.control(null), + billingAddressLine1: this.formBuilder.control(null), + billingAddressLine2: this.formBuilder.control(null), + billingAddressZip: this.formBuilder.control(null), + billingAddressCity: this.formBuilder.control(null), + billingAddressState: this.formBuilder.control(null), + vatCountryCode: this.formBuilder.control(null), + skipVatNr: this.formBuilder.control(false), + vatNr: this.formBuilder.control(null), + italyEInvoicingFiscalCode: this.formBuilder.control(null), + italyEInvoicingReferenceType: this.formBuilder.control(null), + italyEInvoicingReferenceAddresseeCode: this.formBuilder.control(null), + italyEInvoicingReferencePEC: this.formBuilder.control(null), + italyEInvoicingSplitPayment: this.formBuilder.control(null), + additionalInfo: this.formBuilder.group({}) + }); + } + + ngOnInit(): void { + zip(this.userService.getUserIdentity(), this.i18nService.getAvailableLanguages(), this.infoService.getInfo()) + .subscribe(([user, languages, info]) => { + this.languages = languages; + this.i18nService.setPageTitle('user.menu.my-profile', null); + this.invoicingConfiguration = info.invoicingConfiguration; + let values: {[p: string]: any} = { + firstName: user.firstName, + lastName: user.lastName + }; + this.user = user; + const userBillingDetails = user.profile?.billingDetails; + if (userBillingDetails != null) { + values = { + ...values, + billingAddressCompany: userBillingDetails.companyName, + billingAddressLine1: userBillingDetails.addressLine1, + billingAddressLine2: userBillingDetails.addressLine2, + billingAddressZip: userBillingDetails.zip, + billingAddressCity: userBillingDetails.city, + billingAddressState: userBillingDetails.state, + vatCountryCode: userBillingDetails.country, + vatNr: userBillingDetails.taxId, + italyEInvoicingFiscalCode: BookingComponent.optionalGet(userBillingDetails, (i) => i.fiscalCode), + italyEInvoicingReferenceType: BookingComponent.optionalGet(userBillingDetails, (i) => i.referenceType), + italyEInvoicingReferenceAddresseeCode: BookingComponent.optionalGet(userBillingDetails, (i) => i.addresseeCode), + italyEInvoicingReferencePEC: BookingComponent.optionalGet(userBillingDetails, (i) => i.pec), + italyEInvoicingSplitPayment: BookingComponent.optionalGet(userBillingDetails, (i) => i.splitPayment) + }; + } + const additionalData = user.profile?.additionalData; + this.additionalData = additionalData; + if (additionalData != null) { + const additionalInfoGroup = this.userForm.get('additionalInfo') as UntypedFormGroup; + for (const additionalOptionKey of Object.keys(additionalData)) { + additionalInfoGroup.addControl(additionalOptionKey, this.formBuilder.control(additionalData[additionalOptionKey].values[0])); + } + } + this.userForm.patchValue(values); + }); + } + + + save(): void { + this.userService.updateUser(this.userForm.value) + .subscribe(res => { + if (res.success) { + this.feedbackService.showSuccess(this.translateService.instant('my-profile.update.success')); + this.user = res.value; + } else { + handleServerSideValidationError(res.validationErrors, this.userForm); + } + }, err => this.globalErrors = handleServerSideValidationError(err, this.userForm)); + } + + deleteProfile(): void { + const modalRef = this.modalService.open(MyProfileDeleteWarningComponent, {centered: true, backdrop: 'static'}); + modalRef.result.then(() => { + this.userService.deleteProfile().subscribe(response => { + if (!response.empty) { + writeToSessionStorage(DELETE_ACCOUNT_CONFIRMATION, 'y'); + window.location.href = response.targetUrl; + } + }, err => console.log('something went wrong', err)); + }); + } + + get hasAdditionalData(): boolean { + return this.additionalData != null && Object.keys(this.additionalData).length > 0; + } +} diff --git a/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-provider.ts b/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-provider.ts new file mode 100644 index 0000000000..920a9d7535 --- /dev/null +++ b/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-provider.ts @@ -0,0 +1,7 @@ +import {SimplePaymentProvider} from '../payment-provider'; + +export class MolliePaymentProvider extends SimplePaymentProvider { + override get paymentMethodDeferred(): boolean { + return false; + } +} diff --git a/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-proxy.component.html b/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-proxy.component.html new file mode 100644 index 0000000000..0d9eec1737 --- /dev/null +++ b/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-proxy.component.html @@ -0,0 +1,10 @@ +
+
+ + + +
+
+
+
+
\ No newline at end of file diff --git a/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-proxy.component.ts b/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-proxy.component.ts new file mode 100644 index 0000000000..5af2605362 --- /dev/null +++ b/frontend/projects/public/src/app/payment/mollie-payment-proxy/mollie-payment-proxy.component.ts @@ -0,0 +1,43 @@ +import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; + +import {PaymentProvider} from '../payment-provider'; +import {UntypedFormGroup} from '@angular/forms'; +import {MolliePaymentProvider} from './mollie-payment-provider'; +import {PaymentMethod, PaymentProxy} from '../../model/event'; + +@Component({ + selector: 'app-mollie-payment-proxy', + templateUrl: './mollie-payment-proxy.component.html' +}) +export class MolliePaymentProxyComponent implements OnChanges { + + @Input() + method: PaymentMethod; + + @Input() + proxy: PaymentProxy; + + @Input() + parameters: {[key: string]: any}; + + @Input() + overviewForm: UntypedFormGroup; + + @Output() + paymentProvider: EventEmitter = new EventEmitter(); + + private compatibleMethods: PaymentMethod[] = ['CREDIT_CARD', 'IDEAL', 'APPLE_PAY', 'BANCONTACT', 'BELFIUS', 'ING_HOME_PAY', 'KBC', 'PRZELEWY_24']; + + constructor() { } + + ngOnChanges(changes: SimpleChanges): void { + if (this.matchProxyAndMethod && changes.method) { + this.paymentProvider.emit(new MolliePaymentProvider()); + } + } + + public get matchProxyAndMethod(): boolean { + return (this.compatibleMethods.includes(this.method)) && this.proxy === 'MOLLIE'; + } + +} diff --git a/frontend/projects/public/src/app/payment/offline-payment-proxy/offline-payment-proxy.component.html b/frontend/projects/public/src/app/payment/offline-payment-proxy/offline-payment-proxy.component.html new file mode 100644 index 0000000000..17df7c8715 --- /dev/null +++ b/frontend/projects/public/src/app/payment/offline-payment-proxy/offline-payment-proxy.component.html @@ -0,0 +1,9 @@ +
+
+
{{'reservation-page.offline.description'|translate: {'0': parameters? parameters['delayForOfflinePayment'] : '-'} }}
+
+
+
+ +
+
\ No newline at end of file diff --git a/frontend/projects/public/src/app/payment/offline-payment-proxy/offline-payment-proxy.component.ts b/frontend/projects/public/src/app/payment/offline-payment-proxy/offline-payment-proxy.component.ts new file mode 100644 index 0000000000..2fefb12949 --- /dev/null +++ b/frontend/projects/public/src/app/payment/offline-payment-proxy/offline-payment-proxy.component.ts @@ -0,0 +1,46 @@ +import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; +import {PaymentMethod, PaymentProxy} from '../../model/event'; +import {PaymentProvider, SimplePaymentProvider} from '../payment-provider'; +import {UntypedFormGroup} from '@angular/forms'; + +@Component({ + selector: 'app-offline-payment-proxy', + templateUrl: './offline-payment-proxy.component.html' +}) +export class OfflinePaymentProxyComponent implements OnChanges { + + @Input() + method: PaymentMethod; + + @Input() + proxy: PaymentProxy; + + @Input() + parameters: {[key: string]: any}; + + @Input() + overviewForm: UntypedFormGroup; + + @Output() + paymentProvider: EventEmitter = new EventEmitter(); + + constructor() { } + + ngOnChanges(changes: SimpleChanges): void { + if (this.matchProxyAndMethod && changes.method) { + this.paymentProvider.emit(new SimplePaymentProvider()); + } + } + + public get matchProxyAndMethod(): boolean { + return this.method === 'BANK_TRANSFER' && this.proxy === 'OFFLINE'; + } + + handleRecaptchaResponse(recaptchaValue: string) { + this.overviewForm.get('captcha').setValue(recaptchaValue); + } + + public get deferred(): boolean { + return this.parameters['deferred']; + } +} diff --git a/frontend/projects/public/src/app/payment/onsite-payment-proxy/onsite-payment-proxy.component.html b/frontend/projects/public/src/app/payment/onsite-payment-proxy/onsite-payment-proxy.component.html new file mode 100644 index 0000000000..80154e083b --- /dev/null +++ b/frontend/projects/public/src/app/payment/onsite-payment-proxy/onsite-payment-proxy.component.html @@ -0,0 +1,8 @@ +
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/frontend/projects/public/src/app/payment/onsite-payment-proxy/onsite-payment-proxy.component.ts b/frontend/projects/public/src/app/payment/onsite-payment-proxy/onsite-payment-proxy.component.ts new file mode 100644 index 0000000000..6436170649 --- /dev/null +++ b/frontend/projects/public/src/app/payment/onsite-payment-proxy/onsite-payment-proxy.component.ts @@ -0,0 +1,43 @@ +import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; +import {PaymentMethod, PaymentProxy} from '../../model/event'; +import {PaymentProvider, SimplePaymentProvider} from '../payment-provider'; +import {UntypedFormGroup} from '@angular/forms'; + +@Component({ + selector: 'app-onsite-payment-proxy', + templateUrl: './onsite-payment-proxy.component.html' +}) +export class OnsitePaymentProxyComponent implements OnChanges { + + @Input() + method: PaymentMethod; + + @Input() + proxy: PaymentProxy; + + @Input() + parameters: {[key: string]: any}; + + @Input() + overviewForm: UntypedFormGroup; + + @Output() + paymentProvider: EventEmitter = new EventEmitter(); + + constructor() { } + + ngOnChanges(changes: SimpleChanges): void { + if (this.matchProxyAndMethod && changes.method) { + this.paymentProvider.emit(new SimplePaymentProvider()); + } + } + + public get matchProxyAndMethod(): boolean { + return this.method === 'ON_SITE' && this.proxy === 'ON_SITE'; + } + + handleRecaptchaResponse(recaptchaValue: string) { + this.overviewForm.get('captcha').setValue(recaptchaValue); + } + +} diff --git a/frontend/projects/public/src/app/payment/payment-provider.ts b/frontend/projects/public/src/app/payment/payment-provider.ts new file mode 100644 index 0000000000..bd7c592971 --- /dev/null +++ b/frontend/projects/public/src/app/payment/payment-provider.ts @@ -0,0 +1,30 @@ +import {EMPTY, Observable, of} from 'rxjs'; + +export interface PaymentProvider { + readonly paymentMethodDeferred: boolean; + pay(): Observable; + statusNotifications(): Observable; +} + +export class PaymentResult { + constructor(public success: boolean, public gatewayToken: string, public reason: string = null, public reservationChanged = false) {} +} + +export class PaymentStatusNotification { + constructor(public delayed: boolean, public indeterminate: boolean) {} +} + +export class SimplePaymentProvider implements PaymentProvider { + + pay(): Observable { + return of(new PaymentResult(true, null)); + } + + get paymentMethodDeferred(): boolean { + return true; + } + + statusNotifications(): Observable { + return EMPTY; + } +} diff --git a/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-provider.ts b/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-provider.ts new file mode 100644 index 0000000000..9ffe8f4b20 --- /dev/null +++ b/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-provider.ts @@ -0,0 +1,7 @@ +import {SimplePaymentProvider} from '../payment-provider'; + +export class PayPalPaymentProvider extends SimplePaymentProvider { + override get paymentMethodDeferred(): boolean { + return false; + } +} diff --git a/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-proxy.component.html b/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-proxy.component.html new file mode 100644 index 0000000000..b601ea770a --- /dev/null +++ b/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-proxy.component.html @@ -0,0 +1,13 @@ +
+
+
+
+
+
+ +
+
+

{{' '}}

+
+
+
\ No newline at end of file diff --git a/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-proxy.component.ts b/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-proxy.component.ts new file mode 100644 index 0000000000..9dbe81bda7 --- /dev/null +++ b/frontend/projects/public/src/app/payment/paypal-payment-proxy/paypal-payment-proxy.component.ts @@ -0,0 +1,36 @@ +import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; +import {PaymentMethod, PaymentProxy} from '../../model/event'; +import {PaymentProvider} from '../payment-provider'; +import {ReservationInfo} from '../../model/reservation-info'; +import {PayPalPaymentProvider} from './paypal-payment-provider'; + +@Component({ + selector: 'app-paypal-payment-proxy', + templateUrl: './paypal-payment-proxy.component.html', +}) +export class PaypalPaymentProxyComponent implements OnChanges { + + @Input() + method: PaymentMethod; + + @Input() + proxy: PaymentProxy; + + @Input() + reservation: ReservationInfo; + + @Output() + paymentProvider: EventEmitter = new EventEmitter(); + + constructor() { } + + ngOnChanges(changes: SimpleChanges): void { + if (this.matchProxyAndMethod && changes.method) { + this.paymentProvider.emit(new PayPalPaymentProvider()); + } + } + + public get matchProxyAndMethod(): boolean { + return this.proxy === 'PAYPAL'; + } +} diff --git a/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-provider.ts b/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-provider.ts new file mode 100644 index 0000000000..62cf1e5bea --- /dev/null +++ b/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-provider.ts @@ -0,0 +1,7 @@ +import {SimplePaymentProvider} from '../payment-provider'; + +export class SaferpayPaymentProvider extends SimplePaymentProvider { + override get paymentMethodDeferred(): boolean { + return false; + } +} diff --git a/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-proxy.component.html b/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-proxy.component.html new file mode 100644 index 0000000000..c3641d55e4 --- /dev/null +++ b/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-proxy.component.html @@ -0,0 +1,8 @@ +
+
+

Saferpay by SIX

+
+
+
+
+
diff --git a/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-proxy.component.ts b/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-proxy.component.ts new file mode 100644 index 0000000000..6624f7a20b --- /dev/null +++ b/frontend/projects/public/src/app/payment/saferpay-payment-proxy/saferpay-payment-proxy.component.ts @@ -0,0 +1,34 @@ +import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; +import {PaymentMethod, PaymentProxy} from '../../model/event'; +import {ReservationInfo} from '../../model/reservation-info'; +import {PaymentProvider} from '../payment-provider'; +import {SaferpayPaymentProvider} from './saferpay-payment-provider'; + +@Component({ + selector: 'app-saferpay-payment-proxy', + templateUrl: './saferpay-payment-proxy.component.html' +}) +export class SaferpayPaymentProxyComponent implements OnChanges { + @Input() + method: PaymentMethod; + + @Input() + proxy: PaymentProxy; + + @Input() + reservation: ReservationInfo; + + @Output() + paymentProvider: EventEmitter = new EventEmitter(); + + ngOnChanges(changes: SimpleChanges): void { + if (this.matchProxyAndMethod && changes.method) { + this.paymentProvider.emit(new SaferpayPaymentProvider()); + } + } + + public get matchProxyAndMethod(): boolean { + return this.proxy === 'SAFERPAY'; + } + +} diff --git a/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-providers.ts b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-providers.ts new file mode 100644 index 0000000000..e154a257cf --- /dev/null +++ b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-providers.ts @@ -0,0 +1,173 @@ +import {EMPTY, Observable, Subject, Subscriber} from 'rxjs'; +import {PaymentProvider, PaymentResult, PaymentStatusNotification} from '../payment-provider'; +import {TranslateService} from '@ngx-translate/core'; +import {ReservationInfo} from '../../model/reservation-info'; +import {ReservationService} from '../../shared/reservation.service'; +import {PurchaseContext} from '../../model/purchase-context'; + +// global variable defined by stripe when the scripts are loaded +declare const StripeCheckout: any; +// + +export const STRIPE_CHECKOUT_ID_SCRIPT = 'stripe-payment-proxy-checkout'; + +export class StripeCheckoutPaymentProvider implements PaymentProvider { + + constructor( + private translate: TranslateService, + private parameters: { [key: string]: any }, + private reservation: ReservationInfo, + private purchaseContext: PurchaseContext) { + } + + get paymentMethodDeferred(): boolean { + return false; + } + + pay(): Observable { + const obs = new Observable(subscriber => { + this.loadScript(subscriber); + }); + return obs; + } + + loadScript(subscriber: Subscriber) { + if (!document.getElementById(STRIPE_CHECKOUT_ID_SCRIPT)) { + const scriptElem = document.createElement('script'); + scriptElem.id = STRIPE_CHECKOUT_ID_SCRIPT; + scriptElem.src = 'https://checkout.stripe.com/checkout.js'; + scriptElem.async = true; + scriptElem.defer = true; + scriptElem.addEventListener('load', () => { + this.configureAndOpen(subscriber); + }); + document.body.appendChild(scriptElem); + } else if (!window['StripeCheckout']) { + document.getElementById(STRIPE_CHECKOUT_ID_SCRIPT).addEventListener('load', () => { + this.configureAndOpen(subscriber); + }); + } else { + this.configureAndOpen(subscriber); + } + } + + configureAndOpen(subscriber: Subscriber) { + let tokenSubmitted = false; + const stripeHandler = StripeCheckout.configure({ + key: this.parameters['stripe_p_key'], + locale: this.translate.currentLang, + token: (token) => { + tokenSubmitted = true; + subscriber.next(new PaymentResult(true, token.id)); + }, + closed: () => { + if (!tokenSubmitted) { + subscriber.next(new PaymentResult(false, null)); + } + } + }); + stripeHandler.open({ + name: `${this.reservation.firstName} ${this.reservation.lastName}`, + description: this.reservation.orderSummary.descriptionForPayment, + zipCode: false, + allowRememberMe: false, + amount: this.reservation.orderSummary.priceInCents, + currency: this.purchaseContext.currency, + email: this.reservation.email + }); + } + + statusNotifications(): Observable { + return EMPTY; + } +} + +export class StripePaymentV3 implements PaymentProvider { + + private notificationSubject = new Subject(); + + constructor( + private reservationService: ReservationService, + private reservation: ReservationInfo, + private stripeHandler: any, + private card: any + ) { + } + + get paymentMethodDeferred(): boolean { + return false; + } + + pay(): Observable { + + const obs = new Observable(subscriber => { + + this.reservationService.initPayment(this.reservation.id).subscribe(res => { + + if (res.reservationStatusChanged || res.clientSecret == null) { + subscriber.next(new PaymentResult(false, null, null, res.reservationStatusChanged)); + return; + } + + const clientSecret = res.clientSecret; + let billingAddress = null; + if (this.reservation.billingDetails.addressLine1 != null) { + billingAddress = { + line1: this.reservation.billingDetails.addressLine1, + postal_code: this.reservation.billingDetails.zip, + country: StripePaymentV3.toCountryISOCode(this.reservation.billingDetails.country).toLowerCase() + }; + } + const paymentData = { + payment_method_data: { + billing_details: { + name: `${this.reservation.firstName} ${this.reservation.lastName}`, + email: this.reservation.email, + address: billingAddress + } + } + }; + + this.stripeHandler.handleCardPayment(clientSecret, this.card, paymentData).then(cardPaymentResult => { + let retryCount = 0; + let handleCheck: number; + const checkIfPaid = () => { + console.log('checking reservation status...'); + retryCount++; + if (retryCount % 10 === 0) { + this.notificationSubject.next(new PaymentStatusNotification(true, retryCount > 120)); + } + this.reservationService.getPaymentStatus(this.reservation.id).subscribe(status => { + if (cardPaymentResult.error || status.success) { + window.clearInterval(handleCheck); + } + if (status.success) { + subscriber.next(new PaymentResult(true, status.gatewayIdOrNull)); + } else if (cardPaymentResult.error) { + subscriber.error(new PaymentResult(false, null, cardPaymentResult.error.message)); + } else if (status.failure) { + subscriber.error(new PaymentResult(false, null)); + } + }, err => console.log('got error while calling getStatus(). Retrying in 1s', err)); + }; + handleCheck = window.setInterval(checkIfPaid, 1000); + }, err => { + subscriber.error(err); + }); + }, err => { + subscriber.error(err); + }); + }); + return obs; + } + + statusNotifications(): Observable { + return this.notificationSubject.asObservable(); + } + + private static toCountryISOCode(country: string): string { + // The form contains EU-VAT prefix for Greece (EL). + // Here we need the country ISO Code instead + return country === 'EL' ? 'GR' : country; + } +} diff --git a/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.html b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.html new file mode 100644 index 0000000000..4021e83545 --- /dev/null +++ b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.html @@ -0,0 +1,40 @@ +
+
+
+
+
+ + +
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+ +
diff --git a/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.scss b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.scss new file mode 100644 index 0000000000..0ed7407b71 --- /dev/null +++ b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.scss @@ -0,0 +1,37 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; + +.StripeElement { + box-sizing: border-box; + + height: $input-height; + + padding: 0.5rem $input-padding-x; + + border: $input-border-width solid $input-border-color; + border-radius: $input-border-radius; + background-color: $input-bg; + + box-shadow: $input-box-shadow; + -webkit-transition: box-shadow 150ms ease; + transition: box-shadow 150ms ease; +} + +.StripeElement--focus { + background-color: $input-bg; + border-color: $input-focus-border-color; + color: $input-focus-color; + outline: 0; + -webkit-box-shadow: $input-focus-box-shadow; + box-shadow: $input-focus-box-shadow; +} + +.StripeElement--invalid { + border-color: $form-feedback-invalid-color; + -webkit-box-shadow: 0 0 0 $input-focus-width rgba($form-feedback-invalid-color, .25); + box-shadow: 0 0 0 $input-focus-width rgba($form-feedback-invalid-color, .25); +} + +.StripeElement--webkit-autofill { + background-color: #fefde5 !important; +} diff --git a/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.ts b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.ts new file mode 100644 index 0000000000..bc320d6d7c --- /dev/null +++ b/frontend/projects/public/src/app/payment/stripe-payment-proxy/stripe-payment-proxy.component.ts @@ -0,0 +1,146 @@ +import {Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges} from '@angular/core'; +import {PaymentMethod, PaymentProxy} from '../../model/event'; +import {ReservationInfo} from '../../model/reservation-info'; +import {TranslateService} from '@ngx-translate/core'; +import {PaymentProvider} from '../payment-provider'; +import {ReservationService} from '../../shared/reservation.service'; +import {STRIPE_CHECKOUT_ID_SCRIPT, StripeCheckoutPaymentProvider, StripePaymentV3} from './stripe-payment-providers'; +import {removeDOMNode} from '../../shared/event.service'; +import {PurchaseContext} from '../../model/purchase-context'; + +// global variable defined by stripe when the scripts are loaded +declare const Stripe: any; +// + +const STRIPE_V3_ID_SCRIPT = 'stripe-payment-v3-script'; + +@Component({ + selector: 'app-stripe-payment-proxy', + templateUrl: './stripe-payment-proxy.component.html', + styleUrls: ['./stripe-payment-proxy.component.scss'] +}) +export class StripePaymentProxyComponent implements OnChanges, OnDestroy { + + @Input() + purchaseContext: PurchaseContext; + + @Input() + reservation: ReservationInfo; + + @Input() + method: PaymentMethod; + + @Input() + proxy: PaymentProxy; + + @Input() + parameters: { [key: string]: any }; + + @Output() + paymentProvider: EventEmitter = new EventEmitter(); + + constructor( + private translate: TranslateService, + private reservationService: ReservationService) { } + + ngOnChanges(changes: SimpleChanges): void { + if (this.matchProxyAndMethod && changes.method) { + if (this.parameters['enableSCA']) { + this.loadSCA(); + } else { + this.loadNonSCA(); + } + } else { + this.unloadAll(); + } + } + + get useSCA(): boolean { + return this.parameters && this.parameters['enableSCA']; + } + + ngOnDestroy(): void { + this.unloadAll(); + } + + private unloadAll(): void { + const checkoutScript = document.getElementById(STRIPE_CHECKOUT_ID_SCRIPT); + if (checkoutScript && removeDOMNode(checkoutScript)) { + delete window['StripeCheckout']; // TODO: check + } + const stripeV3Script = document.getElementById(STRIPE_V3_ID_SCRIPT); + if (stripeV3Script && removeDOMNode(stripeV3Script)) { + delete window['Stripe']; // TODO: check + } + } + + private loadNonSCA(): void { + this.paymentProvider.emit(new StripeCheckoutPaymentProvider(this.translate, this.parameters, this.reservation, this.purchaseContext)); + } + + public get matchProxyAndMethod(): boolean { + return this.proxy === 'STRIPE'; + } + + + // + private loadSCA(): void { + if (!document.getElementById(STRIPE_V3_ID_SCRIPT)) { + const scriptElem = document.createElement('script'); + scriptElem.id = STRIPE_V3_ID_SCRIPT; + scriptElem.src = 'https://js.stripe.com/v3/'; + scriptElem.async = true; + scriptElem.defer = true; + scriptElem.addEventListener('load', () => { + this.configureSCA(); + }); + document.body.appendChild(scriptElem); + } else if (!window['Stripe']) { + document.getElementById(STRIPE_V3_ID_SCRIPT).addEventListener('load', () => { + this.configureSCA(); + }); + } else { + this.configureSCA(); + } + } + + private configureSCA() { + const options = {}; + + if (this.parameters['stripeConnectedAccount']) { + options['stripeAccount'] = this.parameters['stripeConnectedAccount']; + } + + const stripeHandler = Stripe(this.parameters['stripe_p_key'], options); + const card = stripeHandler.elements({ locale: this.translate.currentLang }).create('card', { + style: { + base: { + color: '#495057', + lineHeight: '18px', + fontFamily: `"Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"`, + fontSmoothing: 'antialiased', + fontSize: '1rem', + '::placeholder': { + color: '#aab7c4' + } + }, + invalid: { + color: '#a94442', + iconColor: '#a94442' + } + } + }); + + card.addEventListener('change', (ev) => { + // TODO: show errors & co + if (ev.complete) { + this.paymentProvider.emit(new StripePaymentV3(this.reservationService, this.reservation, stripeHandler, card)); // enable payment + } else { + this.paymentProvider.emit(null); // -> disable submit buttons by providing an empty payment provider + } + }); + card.mount('#card-element'); + } +} diff --git a/frontend/projects/public/src/app/poll/display-poll/display-poll.component.html b/frontend/projects/public/src/app/poll/display-poll/display-poll.component.html new file mode 100644 index 0000000000..f73e85f521 --- /dev/null +++ b/frontend/projects/public/src/app/poll/display-poll/display-poll.component.html @@ -0,0 +1,37 @@ +
+

{{poll.poll.title[translate.currentLang]}}

+

{{poll.poll.description[translate.currentLang]}}

+ +
+
+
+ +
+
+
+
+
+
+
    +
  • +
    + + +
    +
  • +
+
+
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/frontend/projects/public/src/app/poll/display-poll/display-poll.component.scss b/frontend/projects/public/src/app/poll/display-poll/display-poll.component.scss new file mode 100644 index 0000000000..b77129173b --- /dev/null +++ b/frontend/projects/public/src/app/poll/display-poll/display-poll.component.scss @@ -0,0 +1,29 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/variables"; +.poll-text { + display: inline-block; + vertical-align: top; + padding-left: 1rem; +} + +.poll-title, .poll-description { + display: block; +} + +.poll-title { + font-weight: bold; +} + +.poll-question { + border-bottom:1px solid rgba(0, 0, 0, 0.125);; +} + +.poll-question.last { + border-bottom: none; +} + +.selected { + --bs-bg-opacity: .5; + background-color: $success; +} diff --git a/frontend/projects/public/src/app/poll/display-poll/display-poll.component.ts b/frontend/projects/public/src/app/poll/display-poll/display-poll.component.ts new file mode 100644 index 0000000000..9333775ce8 --- /dev/null +++ b/frontend/projects/public/src/app/poll/display-poll/display-poll.component.ts @@ -0,0 +1,58 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {PollService} from '../shared/poll.service'; +import {combineLatest} from 'rxjs'; +import {PollWithOptions} from '../model/poll-with-options'; +import {TranslateService} from '@ngx-translate/core'; +import {FormGroup, UntypedFormBuilder} from '@angular/forms'; +import {PollVoteForm} from '../model/poll-vote-form'; + +@Component({ + selector: 'app-display-poll', + templateUrl: './display-poll.component.html', + styleUrls: ['./display-poll.component.scss'] +}) +export class DisplayPollComponent implements OnInit { + + + eventShortName: string; + pollId: number; + pin: string; + poll: PollWithOptions; + + pollForm: FormGroup; + pollSubmittedWithSuccess: boolean; + + constructor( + private route: ActivatedRoute, + public translate: TranslateService, + private pollService: PollService, + private fb: UntypedFormBuilder) { } + + ngOnInit(): void { + + this.pollForm = this.fb.group({optionId: null}); + + combineLatest([this.route.parent.params, this.route.params, this.route.queryParams]).subscribe(([parentParams, params, query]) => { + this.eventShortName = parentParams['eventShortName']; + this.pollId = parseInt(params['pollId']); + this.pin = query['pin']; + this.loadPoll() + }); + } + + + loadPoll() { + this.pollService.getPoll(this.eventShortName, this.pollId, this.pin).subscribe(res => { + if (res.success) { + this.poll = res.value; + } + }) + } + + submitChoice() { + this.pollService.registerAnswer(this.eventShortName, this.pollId, {pin: this.pin, optionId: this.pollForm.value.optionId}).subscribe(res => { + this.pollSubmittedWithSuccess = res.success && res.value; + }) + } +} diff --git a/frontend/projects/public/src/app/poll/model/poll-option.ts b/frontend/projects/public/src/app/poll/model/poll-option.ts new file mode 100644 index 0000000000..c6de240fe0 --- /dev/null +++ b/frontend/projects/public/src/app/poll/model/poll-option.ts @@ -0,0 +1,6 @@ +export class PollOption { + id: number; + pollId: number; + title: {[key: string]: string}; + description: {[key: string]: string}; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/poll/model/poll-vote-form.ts b/frontend/projects/public/src/app/poll/model/poll-vote-form.ts new file mode 100644 index 0000000000..715827c3e4 --- /dev/null +++ b/frontend/projects/public/src/app/poll/model/poll-vote-form.ts @@ -0,0 +1,10 @@ +import {FormControl} from '@angular/forms'; + +export interface PollVoteForm { + optionId: FormControl; +} + +export interface PollVotePayload { + pin: string; + optionId: number; +} diff --git a/frontend/projects/public/src/app/poll/model/poll-with-options.ts b/frontend/projects/public/src/app/poll/model/poll-with-options.ts new file mode 100644 index 0000000000..5b1a025869 --- /dev/null +++ b/frontend/projects/public/src/app/poll/model/poll-with-options.ts @@ -0,0 +1,7 @@ +import {PollOption} from './poll-option'; +import {Poll} from './poll'; + +export class PollWithOptions { + poll: Poll; + options: PollOption[]; +} diff --git a/frontend/projects/public/src/app/poll/model/poll.ts b/frontend/projects/public/src/app/poll/model/poll.ts new file mode 100644 index 0000000000..eee19eaa84 --- /dev/null +++ b/frontend/projects/public/src/app/poll/model/poll.ts @@ -0,0 +1,12 @@ +export class Poll { + id: number; + status: PollStatus; + title: {[key: string]: string }; + description: {[key: string]: string }; + allowedTags: string[]; + order: number; + eventId: number; + organizationId: number; +} + +export type PollStatus = 'DRAFT' | 'OPEN' | 'CLOSED' \ No newline at end of file diff --git a/frontend/projects/public/src/app/poll/poll-routing.module.ts b/frontend/projects/public/src/app/poll/poll-routing.module.ts new file mode 100644 index 0000000000..92959172ac --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll-routing.module.ts @@ -0,0 +1,21 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; + +import {PollComponent} from './poll.component'; +import {PollService} from './shared/poll.service'; +import {DisplayPollComponent} from './display-poll/display-poll.component'; +import {PollSelectionComponent} from './poll-selection/poll-selection.component'; + +const routes: Routes = [ + { path: '', component: PollComponent, children: [ + {path: '', component: PollSelectionComponent }, + {path: ':pollId', component: DisplayPollComponent } + ]} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + providers: [PollService] +}) +export class PollRoutingModule { } diff --git a/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.html b/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.html new file mode 100644 index 0000000000..5a9897cb92 --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.html @@ -0,0 +1,34 @@ + +
+
+
+
+

+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+
+
+ + +
diff --git a/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.scss b/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.scss new file mode 100644 index 0000000000..e2c8dbe0f2 --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.scss @@ -0,0 +1,12 @@ +.poll-list .list-group-item { + border-left: 1px solid rgba(0, 0, 0, 0.125);; + border-right: 1px solid rgba(0, 0, 0, 0.125);; +} + +.poll-list .list-group-item:first-child { + border-top: 1px solid rgba(0, 0, 0, 0.125);; +} + +.poll-list .list-group-item:last-child { + border-bottom:1px solid rgba(0, 0, 0, 0.125);; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.ts b/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.ts new file mode 100644 index 0000000000..38a1437e76 --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll-selection/poll-selection.component.ts @@ -0,0 +1,67 @@ +import {Component, OnInit} from '@angular/core'; +import {FormControl, FormGroup, UntypedFormBuilder} from '@angular/forms'; +import {Poll} from '../model/poll'; +import {ActivatedRoute, Router} from '@angular/router'; +import {PollService} from '../shared/poll.service'; +import {TranslateService} from '@ngx-translate/core'; +import {combineLatest} from 'rxjs'; +import {handleServerSideValidationError} from '../../shared/validation-helper'; +import {ErrorDescriptor} from '../../model/validated-response'; + +@Component({ + selector: 'app-poll-selection', + templateUrl: './poll-selection.component.html', + styleUrls: ['./poll-selection.component.scss'] +}) +export class PollSelectionComponent implements OnInit { + + pinForm: FormGroup<{ + pin: FormControl + }>; + polls: Poll[]; + eventShortName: string; + globalErrors: ErrorDescriptor[]; + ready: boolean; + + constructor( + private route: ActivatedRoute, + private router: Router, + private pollService: PollService, + public translate: TranslateService, + private fb: UntypedFormBuilder) { } + + ngOnInit(): void { + this.pinForm = this.fb.group({pin: null}); + combineLatest([this.route.params, this.route.queryParams]).subscribe(([params, query]) => { + this.eventShortName = params['eventShortName']; + if (query['pin']) { + this.loadPolls(this.eventShortName, query['pin']); + } else { + this.ready = true; + } + }); + } + + private loadPolls(eventShortName: string, pin: string) { + this.ready = false; + this.pollService.getAllPolls(eventShortName, pin).subscribe(res => { + if (res.success) { + this.router.navigate([], {queryParamsHandling: 'merge', queryParams: {pin: pin}}); + this.polls = res.value; + if (this.polls.length === 1) { + this.router.navigate([this.polls[0].id], {relativeTo: this.route, queryParamsHandling: 'merge', queryParams: {pin: pin}}); + } + } + this.ready = true; + }, (err) => { + this.globalErrors = handleServerSideValidationError(err, this.pinForm); + this.ready = true; + }); + } + + confirmPin() { + const pin = this.pinForm.value.pin; + this.loadPolls(this.eventShortName, pin); + } + +} diff --git a/frontend/projects/public/src/app/poll/poll.component.html b/frontend/projects/public/src/app/poll/poll.component.html new file mode 100644 index 0000000000..ec2f790e01 --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll.component.html @@ -0,0 +1,9 @@ +
+
+
+
+
+ +
+
+
diff --git a/frontend/projects/public/src/app/poll/poll.component.scss b/frontend/projects/public/src/app/poll/poll.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/public/src/app/poll/poll.component.ts b/frontend/projects/public/src/app/poll/poll.component.ts new file mode 100644 index 0000000000..6cf374dece --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll.component.ts @@ -0,0 +1,33 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {EventService} from '../shared/event.service'; +import {TranslateService} from '@ngx-translate/core'; +import {Event} from '../model/event'; +import {I18nService} from '../shared/i18n.service'; + +@Component({ + selector: 'app-live-poll', + templateUrl: './poll.component.html', + styleUrls: ['./poll.component.scss'] +}) +export class PollComponent implements OnInit { + + event: Event + + constructor( + private route: ActivatedRoute, + private eventService: EventService, + public translate: TranslateService, + public i18nService: I18nService) { } + + ngOnInit(): void { + + this.route.params.subscribe(params => { + const eventShortName = params['eventShortName']; + this.eventService.getEvent(eventShortName).subscribe(ev => { + this.i18nService.setPageTitle('poll.page.title', ev); + this.event = ev; + }); + }); + } +} diff --git a/frontend/projects/public/src/app/poll/poll.module.ts b/frontend/projects/public/src/app/poll/poll.module.ts new file mode 100644 index 0000000000..58aac2acd4 --- /dev/null +++ b/frontend/projects/public/src/app/poll/poll.module.ts @@ -0,0 +1,24 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {PollRoutingModule} from './poll-routing.module'; +import {PollComponent} from './poll.component'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {DisplayPollComponent} from './display-poll/display-poll.component'; +import {TranslateModule} from '@ngx-translate/core'; +import {SharedModule} from '../shared/shared.module'; +import {PollSelectionComponent} from './poll-selection/poll-selection.component'; + + +@NgModule({ + declarations: [PollComponent, DisplayPollComponent, PollSelectionComponent], + imports: [ + TranslateModule.forChild(), + CommonModule, + PollRoutingModule, + FormsModule, + ReactiveFormsModule, + SharedModule + ] +}) +export class PollModule { } diff --git a/frontend/projects/public/src/app/poll/shared/poll.service.ts b/frontend/projects/public/src/app/poll/shared/poll.service.ts new file mode 100644 index 0000000000..972eca9688 --- /dev/null +++ b/frontend/projects/public/src/app/poll/shared/poll.service.ts @@ -0,0 +1,26 @@ +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import {Poll} from '../model/poll'; +import {PollWithOptions} from '../model/poll-with-options'; +import {PollVotePayload} from '../model/poll-vote-form'; +import {ValidatedResponse} from '../../model/validated-response'; +import {HttpClient} from '@angular/common/http'; + +@Injectable() +export class PollService { + + constructor(private http: HttpClient) { } + + + getAllPolls(eventName: string, pin: string): Observable> { + return this.http.get>(`/api/v2/public/event/${eventName}/poll`, {params: {pin: pin}}); + } + + getPoll(eventName: string, pollId: number, pin: string): Observable> { + return this.http.get>(`/api/v2/public/event/${eventName}/poll/${pollId}`, {params: {pin: pin}}); + } + + registerAnswer(eventName: string, pollId: number, pollForm: PollVotePayload): Observable> { + return this.http.post>(`/api/v2/public/event/${eventName}/poll/${pollId}/answer`, pollForm); + } +} diff --git a/frontend/projects/public/src/app/price-tag/price-tag.component.html b/frontend/projects/public/src/app/price-tag/price-tag.component.html new file mode 100644 index 0000000000..a04afc93d1 --- /dev/null +++ b/frontend/projects/public/src/app/price-tag/price-tag.component.html @@ -0,0 +1,11 @@ +
+
+ {{currencyDescriptor.symbol}}{{' '}} + {{formattedPrice}}{{' '}}{{discountedPrice}} + {{formattedPrice}} +
+
 
+
+ {{(purchaseContext.vatIncluded ? 'show-event.incVat' : 'show-event.excVat') | translate:{'0': purchaseContext.vat, '1': ('common.vat' | translate)} }} +
+
diff --git a/frontend/projects/public/src/app/price-tag/price-tag.component.ts b/frontend/projects/public/src/app/price-tag/price-tag.component.ts new file mode 100644 index 0000000000..1bb9442490 --- /dev/null +++ b/frontend/projects/public/src/app/price-tag/price-tag.component.ts @@ -0,0 +1,58 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {CurrencyDescriptor} from '../model/event'; +import {PurchaseContextPriceDescriptor} from '../model/purchase-context'; + +@Component({ + selector: 'app-price-tag', + templateUrl: './price-tag.component.html' +}) +export class PriceTagComponent implements OnInit { + @Input() + purchaseContext: PurchaseContextPriceDescriptor; + @Input() + formattedPrice: string; + @Input() + discountedPrice: string; + @Input() + showTaxDetails: boolean; + @Input() + displayTextInline: boolean; + @Input() + singleLineLayout: boolean; + @Input() + showDiscount: boolean; + + displayCurrencySymbol: boolean; + currencyDescriptor: CurrencyDescriptor; + + ngOnInit(): void { + this.currencyDescriptor = this.purchaseContext.currencyDescriptor; + this.displayCurrencySymbol = this.currencyDescriptor && this.currencyDescriptor.symbol !== this.currencyDescriptor.code; + } + + get displayDiscountedPrice(): boolean { + return this.showDiscount && this.discountedPrice != null && this.discountedPrice !== this.formattedPrice; + } + + get showTaxes(): boolean { + return this.showTaxDetails && (Number(this.purchaseContext.vat) || 0) > 0.0; + } + + removeRedundantPrecision(input: string): string { + let substringEnd = input.lastIndexOf('.'); + if (substringEnd > -1) { + const fraction = input.substring(substringEnd + 1); + let additionalChars = 1; + for (let i = 0; i < fraction.length; i++) { + if (fraction.charAt(i) !== '0') { + additionalChars++; + } + } + if (additionalChars > 1) { + substringEnd += additionalChars; + } + return input.substring(0, substringEnd); + } + return input; + } +} diff --git a/frontend/projects/public/src/app/purchase-context-container/purchase-context-container.component.html b/frontend/projects/public/src/app/purchase-context-container/purchase-context-container.component.html new file mode 100644 index 0000000000..5fbb9eccfc --- /dev/null +++ b/frontend/projects/public/src/app/purchase-context-container/purchase-context-container.component.html @@ -0,0 +1,8 @@ +
+
+ +
+ +
+
+
diff --git a/frontend/projects/public/src/app/purchase-context-container/purchase-context-container.component.ts b/frontend/projects/public/src/app/purchase-context-container/purchase-context-container.component.ts new file mode 100644 index 0000000000..646e6e4b35 --- /dev/null +++ b/frontend/projects/public/src/app/purchase-context-container/purchase-context-container.component.ts @@ -0,0 +1,14 @@ +import {Component, Input} from '@angular/core'; +import {PurchaseContext} from '../model/purchase-context'; + +@Component({ + selector: 'app-purchase-context-container', + templateUrl: './purchase-context-container.component.html' +}) +export class PurchaseContextContainerComponent { + @Input() + purchaseContext: PurchaseContext; + + @Input() + displayFooterLinks = true; +} diff --git a/frontend/projects/public/src/app/recaptcha/recaptcha.component.ts b/frontend/projects/public/src/app/recaptcha/recaptcha.component.ts new file mode 100644 index 0000000000..f48d10248a --- /dev/null +++ b/frontend/projects/public/src/app/recaptcha/recaptcha.component.ts @@ -0,0 +1,101 @@ +import {AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild} from '@angular/core'; +import {TranslateService} from '@ngx-translate/core'; +import {Subscription} from 'rxjs'; + + +declare const grecaptcha: any; + +let idCallback = 0; + +@Component({ + selector: 'app-recaptcha', + template: '
' +}) +export class RecaptchaComponent implements OnDestroy, AfterViewInit { + + @Input() + apiKey: string; + + private langSub: Subscription; + + @ViewChild('targetElement', { static: true }) + private targetElement: ElementRef; + + @Output() + recaptchaResponse: EventEmitter = new EventEmitter(); + + + private widgetId: any = null; + + constructor(private translate: TranslateService) { } + + ngAfterViewInit() { + if (!document.getElementById('recaptcha-api-script')) { + const scriptElem = document.createElement('script'); + + idCallback++; + + const callBackName = `onloadRecaptchaCallback${idCallback}`; + + scriptElem.src = `https://www.google.com/recaptcha/api.js?onload=${callBackName}&render=explicit`; + scriptElem.id = 'recaptcha-api-script'; + scriptElem.async = true; + scriptElem.defer = true; + + window[callBackName] = () => { + this.enableRecaptcha(); + }; + document.body.appendChild(scriptElem); + } else if (!window['grecaptcha']) { + // wait until it's available + const waiter = () => { + if (window['grecaptcha']) { + this.enableRecaptcha(); + } else { + setTimeout(waiter, 100); + } + }; + setTimeout(waiter, 100); + } else { + this.enableRecaptcha(); + } + + this.langSub = this.translate.onLangChange.subscribe(change => { + this.enableRecaptcha(); + }); + } + + ngOnDestroy() { + if (this.langSub) { + this.langSub.unsubscribe(); + } + if (window['grecaptcha'] && this.widgetId !== null) { + grecaptcha.reset(this.widgetId); + } + } + + enableRecaptcha() { + + // delete container if present + const range = document.createRange(); + range.selectNodeContents(this.targetElement.nativeElement); + range.deleteContents(); + // + + const container = document.createElement('div'); + this.targetElement.nativeElement.appendChild(container); + // + + + if (window['grecaptcha']) { + this.widgetId = grecaptcha.render(container, { + sitekey: this.apiKey, + hl: this.translate.currentLang, + callback: (res) => { + this.recaptchaResponse.emit(res); + } + }); + } + } + +} diff --git a/frontend/projects/public/src/app/remove-event-css.guard.ts b/frontend/projects/public/src/app/remove-event-css.guard.ts new file mode 100644 index 0000000000..229cf5c9de --- /dev/null +++ b/frontend/projects/public/src/app/remove-event-css.guard.ts @@ -0,0 +1,15 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree} from '@angular/router'; +import {Observable} from 'rxjs'; +import {removeAllCustomEventCss} from './shared/custom-css-helper'; + +@Injectable({ + providedIn: 'root' +}) +export class RemoveEventCssGuard implements CanActivate { + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { + removeAllCustomEventCss(); + return true; + } + +} diff --git a/frontend/projects/public/src/app/reservation/animated-dots/animated-dots.component.scss b/frontend/projects/public/src/app/reservation/animated-dots/animated-dots.component.scss new file mode 100644 index 0000000000..e04a3bb59e --- /dev/null +++ b/frontend/projects/public/src/app/reservation/animated-dots/animated-dots.component.scss @@ -0,0 +1,17 @@ +/* source: https://stackoverflow.com/a/24349758 */ + +@keyframes dots-1 { from { opacity: 0; } 25% { opacity: 1; } } +@keyframes dots-2 { from { opacity: 0; } 50% { opacity: 1; } } +@keyframes dots-3 { from { opacity: 0; } 75% { opacity: 1; } } + +.dots span { + animation: dots-1 1s infinite steps(1); +} + +.dots span:first-child + span { + animation-name: dots-2; +} + +.dots span:first-child + span + span { + animation-name: dots-3; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/animated-dots/animated-dots.component.ts b/frontend/projects/public/src/app/reservation/animated-dots/animated-dots.component.ts new file mode 100644 index 0000000000..30f62d5cbe --- /dev/null +++ b/frontend/projects/public/src/app/reservation/animated-dots/animated-dots.component.ts @@ -0,0 +1,10 @@ +import {Component} from '@angular/core'; + +@Component({ + selector: 'app-animated-dots', + template: '...', + styleUrls: ['./animated-dots.component.scss'] +}) +export class AnimatedDotsComponent { + +} diff --git a/frontend/projects/public/src/app/reservation/booking/booking.component.html b/frontend/projects/public/src/app/reservation/booking/booking.component.html new file mode 100644 index 0000000000..1311c54160 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/booking/booking.component.html @@ -0,0 +1,143 @@ + + +
+ + + + + +
+ + + + + + + +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + + +
+ +
+
+
+ + +
+ + +
+ + + +

+ +
+ + +
+ + +
+
+
+
+

+ + {{' '}}{{'reservation-page-complete.ticket-nr' | translate}} +

+
+ +
+
+
{{tc.name}}
+ +
+
+
+
+
+ +
+ + +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+ + +
+ +
+
+ +
+
+ +
+
+
+
+ +
diff --git a/frontend/projects/public/src/app/reservation/booking/booking.component.ts b/frontend/projects/public/src/app/reservation/booking/booking.component.ts new file mode 100644 index 0000000000..e5001c9a90 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/booking/booking.component.ts @@ -0,0 +1,327 @@ +import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {ReservationService} from '../../shared/reservation.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms'; +import {TicketService} from '../../shared/ticket.service'; +import {BillingDetails, ItalianEInvoicing, ReservationInfo, ReservationSubscriptionInfo, TicketsByTicketCategory} from '../../model/reservation-info'; +import {Observable, of, Subject, zip} from 'rxjs'; +import {getErrorObject, handleServerSideValidationError} from '../../shared/validation-helper'; +import {I18nService} from '../../shared/i18n.service'; +import {Ticket} from '../../model/ticket'; +import {TranslateService} from '@ngx-translate/core'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {ErrorDescriptor} from '../../model/validated-response'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {ReservationExpiredComponent} from '../expired-notification/reservation-expired.component'; +import {CancelReservationComponent} from '../cancel-reservation/cancel-reservation.component'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; +import {PurchaseContext} from '../../model/purchase-context'; +import {WarningModalComponent} from '../../shared/warning-modal/warning-modal.component'; +import {SearchParams} from '../../model/search-params'; +import {UserService} from '../../shared/user.service'; +import {ANONYMOUS, User} from '../../model/user'; +import {first} from 'rxjs/operators'; +import {FeedbackService} from '../../shared/feedback/feedback.service'; +import {ReservationStatusChanged} from '../../model/embedding-configuration'; +import {embedded} from '../../shared/util'; + +@Component({ + selector: 'app-booking', + templateUrl: './booking.component.html' +}) +export class BookingComponent implements OnInit, AfterViewInit { + + reservationInfo: ReservationInfo; + purchaseContext: PurchaseContext; + contactAndTicketsForm: UntypedFormGroup; + private publicIdentifier: string; + reservationId: string; + expired: boolean; + globalErrors: ErrorDescriptor[]; + @ViewChild('invoiceAnchor') + private invoiceElement: ElementRef; + private doScroll = new Subject(); + purchaseContextType: PurchaseContextType; + + ticketCounts: number; + + enableAttendeeAutocomplete: boolean; + displayLoginSuggestion: boolean; + + public static optionalGet(billingDetails: BillingDetails, consumer: (b: ItalianEInvoicing) => T, userBillingDetails?: BillingDetails): T | null { + const italianEInvoicing = billingDetails.invoicingAdditionalInfo.italianEInvoicing; + if (italianEInvoicing != null) { + return consumer(italianEInvoicing); + } + const userItalianEInvoicing = userBillingDetails?.invoicingAdditionalInfo?.italianEInvoicing; + if (userItalianEInvoicing != null) { + return consumer(userItalianEInvoicing); + } + return null; + } + + private static isUUID(v: string): boolean { + const r = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; + return v.match(r) !== null; + } + + constructor( + private route: ActivatedRoute, + private router: Router, + private reservationService: ReservationService, + private ticketService: TicketService, + private purchaseContextService: PurchaseContextService, + private formBuilder: UntypedFormBuilder, + private i18nService: I18nService, + private translate: TranslateService, + private analytics: AnalyticsService, + private modalService: NgbModal, + private userService: UserService, + private feedbackService: FeedbackService) { } + + public ngOnInit(): void { + zip(this.route.data, this.route.params, this.userService.authenticationStatus.pipe(first())).subscribe(([data, params, authStatus]) => { + + const user: User | undefined = authStatus.user; + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + this.purchaseContextType = data.type; + this.displayLoginSuggestion = authStatus.enabled && authStatus.user === ANONYMOUS; + + zip( + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier), + this.reservationService.getReservationInfo(this.reservationId) + ).subscribe(([purchaseContext, reservationInfo]) => { + this.purchaseContext = purchaseContext; + this.reservationInfo = reservationInfo; + + this.i18nService.setPageTitle('reservation-page.header.title', purchaseContext); + + const invoiceRequested = purchaseContext.invoicingConfiguration.onlyInvoice ? true : reservationInfo.invoiceRequested; + + // + this.ticketCounts = 0; + this.reservationInfo.ticketsByCategory.forEach(t => { + this.ticketCounts += t.tickets.length; + }); + + + // auto complete (copy by default first/lastname + email to ticket) is enabled only if we have only + // one ticket + if (this.ticketCounts === 1 && this.purchaseContext.assignmentConfiguration.enableAttendeeAutocomplete) { + this.enableAttendeeAutocomplete = true; + } + // + + // + + const billingDetails = this.reservationInfo.billingDetails; + const userBillingDetails = user?.profile?.billingDetails; + + this.contactAndTicketsForm = this.formBuilder.group({ + firstName: this.formBuilder.control(this.reservationInfo.firstName || user?.firstName, [Validators.required, Validators.maxLength(255)]), + lastName: this.formBuilder.control(this.reservationInfo.lastName || user?.lastName, [Validators.required, Validators.maxLength(255)]), + email: this.formBuilder.control(this.reservationInfo.email || user?.emailAddress, [Validators.required, Validators.maxLength(255)]), + tickets: this.buildTicketsFormGroup(this.reservationInfo.ticketsByCategory, user), + invoiceRequested: invoiceRequested, + addCompanyBillingDetails: this.reservationInfo.addCompanyBillingDetails || userBillingDetails?.companyName != null, + billingAddressCompany: billingDetails.companyName || userBillingDetails?.companyName, + billingAddressLine1: billingDetails.addressLine1 || userBillingDetails?.addressLine1, + billingAddressLine2: billingDetails.addressLine2 || userBillingDetails?.addressLine2, + billingAddressZip: billingDetails.zip || userBillingDetails?.zip, + billingAddressCity: billingDetails.city || userBillingDetails?.city, + billingAddressState: billingDetails.state || userBillingDetails?.state, + vatCountryCode: billingDetails.country || userBillingDetails?.country, + customerReference: this.reservationInfo.customerReference, + vatNr: billingDetails.taxId || userBillingDetails?.taxId, + skipVatNr: this.reservationInfo.skipVatNr, + italyEInvoicingFiscalCode: BookingComponent.optionalGet(billingDetails, (i) => i.fiscalCode, userBillingDetails), + italyEInvoicingReferenceType: BookingComponent.optionalGet(billingDetails, (i) => i.referenceType, userBillingDetails), + italyEInvoicingReferenceAddresseeCode: BookingComponent.optionalGet(billingDetails, (i) => i.addresseeCode, userBillingDetails), + italyEInvoicingReferencePEC: BookingComponent.optionalGet(billingDetails, (i) => i.pec, userBillingDetails), + italyEInvoicingSplitPayment: BookingComponent.optionalGet(billingDetails, (i) => i.splitPayment, userBillingDetails), + postponeAssignment: false, + differentSubscriptionOwner: false, + subscriptionOwner: this.buildSubscriptionOwnerFormGroup(this.reservationInfo.subscriptionInfos, user) + }); + + setTimeout(() => this.doScroll.next(this.invoiceElement != null)); + + this.analytics.pageView(purchaseContext.analyticsConfiguration); + }); + }); + } + + ngAfterViewInit(): void { + zip(this.route.queryParams, this.doScroll.asObservable()) + .subscribe(results => { + const requestInvoice: boolean = !!results[0].requestInvoice; + if (requestInvoice && results[1]) { + this.contactAndTicketsForm.get('invoiceRequested').setValue(true); + this.invoiceElement.nativeElement.scrollIntoView(true); + } + }); + } + + private buildSubscriptionOwnerFormGroup(subscriptionInfos: Array | undefined, user?: User): UntypedFormGroup { + if (subscriptionInfos != null) { + const subscriptionInfo = subscriptionInfos[0]; + const email = subscriptionInfo.owner?.email || (this.emailEditForbidden ? this.reservationInfo.email : null) || user?.emailAddress; + return this.formBuilder.group({ + firstName: subscriptionInfo.owner?.firstName || user?.firstName, + lastName: subscriptionInfo.owner?.lastName || user?.lastName, + email + }); + } else { + return null; + } + } + + private buildTicketsFormGroup(ticketsByCategory: TicketsByTicketCategory[], user: User): UntypedFormGroup { + const tickets = {}; + ticketsByCategory.forEach(t => { + t.tickets.forEach((ticket, idx) => { + tickets[ticket.uuid] = this.ticketService.buildFormGroupForTicket(ticket, idx === 0 ? user : undefined); + }); + }); + return this.formBuilder.group(tickets); + } + + private removeUnnecessaryFields(): void { + // check invoice data, remove company data if private invoice has been chosen + if (this.contactAndTicketsForm.get('invoiceRequested').value && !this.contactAndTicketsForm.get('addCompanyBillingDetails').value) { + ['billingAddressCompany', 'vatNr', 'skipVatNr'].forEach(n => this.contactAndTicketsForm.get(n).setValue(null)); + } + } + + submitForm(): void { + this.removeUnnecessaryFields(); + this.validateToOverview(false); + } + + private validateToOverview(ignoreWarnings: boolean): void { + this.reservationService.validateToOverview(this.reservationId, this.contactAndTicketsForm.value, this.translate.currentLang, ignoreWarnings).subscribe(res => { + if (res.success && (!res.warnings || res.warnings.length === 0 || ignoreWarnings)) { + let o: Observable = of(true); + if (this.route.snapshot.queryParamMap.has('subscription') && BookingComponent.isUUID(this.route.snapshot.queryParamMap.get('subscription'))) { + // try to apply the subscription + const subscriptionCode = this.route.snapshot.queryParamMap.get('subscription'); + o = this.reservationService.applySubscriptionCode(this.reservationId, subscriptionCode, this.reservationInfo.email); + } + o.subscribe( + _ => this.proceedToOverview(), + // if there is an error, we proceed anyway + () => this.proceedToOverview() + ); + } else if (res.success) { + // display warnings + const modalRef = this.modalService.open(WarningModalComponent, {centered: true, backdrop: 'static'}); + const firstWarning = res.warnings[0]; + modalRef.componentInstance.message = firstWarning.code; + const params: {[key: string]: string} = {}; + firstWarning.params.forEach((v, i) => params['' + i] = v); + modalRef.componentInstance.parameters = params; + modalRef.result.then(() => this.validateToOverview(true)); + } + }, (err) => { + this.globalErrors = handleServerSideValidationError(err, this.contactAndTicketsForm); + }); + } + + private proceedToOverview(): Promise { + return this.router.navigate([this.purchaseContextType, this.publicIdentifier, 'reservation', this.reservationId, 'overview'], { + queryParams: SearchParams.transformParams(this.route.snapshot.queryParams, this.route.snapshot.params) + }); + } + + cancelPendingReservation() { + this.modalService.open(CancelReservationComponent, {centered: true}).result.then(res => { + if (res === 'yes') { + this.reservationService.cancelPendingReservation(this.reservationId).subscribe(() => { + this.handleCancelOrExpired(); + }); + } + }, () => {}); + } + + handleExpired(expired: boolean): void { + setTimeout(() => { + if (!this.expired) { + this.expired = expired; + this.modalService.open(ReservationExpiredComponent, {centered: true, backdrop: 'static'}) + .result.then(() => this.handleCancelOrExpired()); + } + }); + } + + private handleCancelOrExpired(): void { + if (embedded && this.purchaseContext.embeddingConfiguration.enabled) { + window.parent.postMessage( + new ReservationStatusChanged('CANCELLED', this.reservationId), + this.purchaseContext.embeddingConfiguration.notificationOrigin + ); + } else { + this.router.navigate([this.purchaseContextType, this.publicIdentifier], {replaceUrl: true}); + } + } + + handleInvoiceRequestedChange() { + // set addCompanyBillingDetails to false if it's null + if (this.contactAndTicketsForm.value.addCompanyBillingDetails === null) { + this.contactAndTicketsForm.get('addCompanyBillingDetails').setValue(false); + } + } + + handleAutocomplete(fieldName: string, value: string) { + if (this.enableAttendeeAutocomplete) { + const ticketUUID = Object.keys(this.contactAndTicketsForm.get('tickets').value)[0]; + const targetControl = this.contactAndTicketsForm.get(`tickets.${ticketUUID}.${fieldName}`); + if (targetControl.pristine && (targetControl.value == null || targetControl.value === '')) { + targetControl.setValue(value); + } + } + } + + getTicketForm(ticket: Ticket): UntypedFormGroup { + return this.contactAndTicketsForm.get('tickets.' + ticket.uuid) as UntypedFormGroup; + } + + getSubscriptionForm(): UntypedFormGroup { + return this.contactAndTicketsForm.get('subscriptionOwner') as UntypedFormGroup; + } + + copyContactInfoTo(ticket: Ticket) { + ['firstName', 'lastName', 'email'].forEach(field => { + const val = this.contactAndTicketsForm.get(field).value; + this.contactAndTicketsForm.get(`tickets.${ticket.uuid}.${field}`).setValue(val); + }); + } + + login(): void { + // save reservation status + const redirectToLogin = () => { + window.location.href = `/openid/authentication?reservation=${this.reservationId}&contextType=${this.purchaseContextType}&id=${this.publicIdentifier}`; + }; + this.reservationService.validateToOverview(this.reservationId, this.contactAndTicketsForm.value, this.translate.currentLang, false) + .subscribe(() => { + // reservation is now saved. We can proceed to login + redirectToLogin(); + }, error => { + const errorObj = getErrorObject(error); + if (errorObj != null) { + // reservation is not in a valid state. Proceed anyway + redirectToLogin(); + } else { + this.feedbackService.showError(this.translate.instant('reservation-page.cannot-login.error')); + } + }); + } + + get showContactData(): boolean { + return !embedded || !this.reservationInfo.metadata.hideContactData; + } + + get emailEditForbidden(): boolean { + return this.reservationInfo.metadata.lockEmailEdit; + } +} diff --git a/frontend/projects/public/src/app/reservation/cancel-reservation/cancel-reservation.component.ts b/frontend/projects/public/src/app/reservation/cancel-reservation/cancel-reservation.component.ts new file mode 100644 index 0000000000..6c404fd3dd --- /dev/null +++ b/frontend/projects/public/src/app/reservation/cancel-reservation/cancel-reservation.component.ts @@ -0,0 +1,11 @@ +import {Component} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-cancel-reservation', + templateUrl: './cancel-reservation.html' +}) +export class CancelReservationComponent { + constructor(public activeModal: NgbActiveModal) { + } +} diff --git a/frontend/projects/public/src/app/reservation/cancel-reservation/cancel-reservation.html b/frontend/projects/public/src/app/reservation/cancel-reservation/cancel-reservation.html new file mode 100644 index 0000000000..76b2ead888 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/cancel-reservation/cancel-reservation.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/deferred-offline-payment/deferred-offline-payment.component.html b/frontend/projects/public/src/app/reservation/deferred-offline-payment/deferred-offline-payment.component.html new file mode 100644 index 0000000000..49a1368bbd --- /dev/null +++ b/frontend/projects/public/src/app/reservation/deferred-offline-payment/deferred-offline-payment.component.html @@ -0,0 +1,22 @@ + +
+
+

+

+
+ + + +
{{'reservation-page-complete.order-information' | translate: {'0': reservationId, '1': reservationInfo.firstName + ' ' + reservationInfo.lastName} }}
+
+
+
+ +
+

+
+
+
+
\ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/deferred-offline-payment/deferred-offline-payment.component.ts b/frontend/projects/public/src/app/reservation/deferred-offline-payment/deferred-offline-payment.component.ts new file mode 100644 index 0000000000..22d0066944 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/deferred-offline-payment/deferred-offline-payment.component.ts @@ -0,0 +1,48 @@ +import {Component, OnInit} from '@angular/core'; +import {ReservationInfo} from '../../model/reservation-info'; +import {ActivatedRoute} from '@angular/router'; +import {ReservationService} from '../../shared/reservation.service'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../../shared/i18n.service'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {zip} from 'rxjs'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; +import {PurchaseContext} from '../../model/purchase-context'; + +@Component({ + selector: 'app-deferred-offline-payment', + templateUrl: './deferred-offline-payment.component.html' +}) +export class DeferredOfflinePaymentComponent implements OnInit { + + reservationInfo: ReservationInfo; + purchaseContextType: PurchaseContextType; + publicIdentifier: string; + reservationId: string; + purchaseContext: PurchaseContext; + + constructor( + private route: ActivatedRoute, + private purchaseContextService: PurchaseContextService, + private reservationService: ReservationService, + public translate: TranslateService, + private i18nService: I18nService, + private analytics: AnalyticsService) { } + + ngOnInit(): void { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + this.purchaseContextType = data.type; + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + zip( + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier), + this.reservationService.getReservationInfo(this.reservationId) + ).subscribe(([ev, reservationInfo]) => { + this.purchaseContext = ev; + this.reservationInfo = reservationInfo; + this.i18nService.setPageTitle('reservation-page-waiting.header.title', ev); + this.analytics.pageView(ev.analyticsConfiguration); + }); + }); + } +} diff --git a/frontend/projects/public/src/app/reservation/download-ticket/download-ticket.component.html b/frontend/projects/public/src/app/reservation/download-ticket/download-ticket.component.html new file mode 100644 index 0000000000..58740ac589 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/download-ticket/download-ticket.component.html @@ -0,0 +1,29 @@ + + + diff --git a/frontend/projects/public/src/app/reservation/download-ticket/download-ticket.component.ts b/frontend/projects/public/src/app/reservation/download-ticket/download-ticket.component.ts new file mode 100644 index 0000000000..4d602dc4d7 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/download-ticket/download-ticket.component.ts @@ -0,0 +1,34 @@ +import {Component, Input} from '@angular/core'; +import {Ticket} from '../../model/ticket'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; +import {WalletConfiguration} from '../../model/info'; + +@Component({ + selector: 'app-download-ticket', + templateUrl: './download-ticket.component.html' +}) +export class DownloadTicketComponent { + @Input() + ticket: Ticket; + + @Input() + eventName: string; + + @Input() + walletConfiguration: WalletConfiguration; + + constructor(private activeModal: NgbActiveModal) { + } + + close(): void { + this.activeModal.dismiss(); + } + + get gWalletEnabled(): boolean { + return this.walletConfiguration != null && this.walletConfiguration.gWalletEnabled; + } + + get passEnabled(): boolean { + return this.walletConfiguration != null && this.walletConfiguration.passEnabled; + } +} diff --git a/frontend/projects/public/src/app/reservation/error/error.component.html b/frontend/projects/public/src/app/reservation/error/error.component.html new file mode 100644 index 0000000000..d3aab16b76 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/error/error.component.html @@ -0,0 +1,5 @@ + +

+

+

{{'reservation-page-error-status.your-reservation-identifier' | translate: {'0': reservationId} }}

+
diff --git a/frontend/projects/public/src/app/reservation/error/error.component.ts b/frontend/projects/public/src/app/reservation/error/error.component.ts new file mode 100644 index 0000000000..2a3fd836f6 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/error/error.component.ts @@ -0,0 +1,35 @@ +import {Component, OnInit} from '@angular/core'; +import {I18nService} from '../../shared/i18n.service'; +import {ActivatedRoute} from '@angular/router'; +import {PurchaseContext} from '../../model/purchase-context'; +import {zip} from 'rxjs'; +import {PurchaseContextService} from '../../shared/purchase-context.service'; + +@Component({ + selector: 'app-error', + templateUrl: './error.component.html' +}) +export class ErrorComponent implements OnInit { + + + reservationId: string; + purchaseContext: PurchaseContext; + + constructor( + private route: ActivatedRoute, + private purchaseContextService: PurchaseContextService, + private i18nService: I18nService) { } + + ngOnInit() { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + const publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + const purchaseContextType = data.type; + this.purchaseContextService.getContext(purchaseContextType, publicIdentifier).subscribe(ev => { + this.purchaseContext = ev; + this.i18nService.setPageTitle('reservation-page-not-found.header.title', ev); + }); + }); + } + +} diff --git a/frontend/projects/public/src/app/reservation/expired-notification/reservation-expired.component.html b/frontend/projects/public/src/app/reservation/expired-notification/reservation-expired.component.html new file mode 100644 index 0000000000..9a1c9019f7 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/expired-notification/reservation-expired.component.html @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/expired-notification/reservation-expired.component.ts b/frontend/projects/public/src/app/reservation/expired-notification/reservation-expired.component.ts new file mode 100644 index 0000000000..e36aa73dc3 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/expired-notification/reservation-expired.component.ts @@ -0,0 +1,13 @@ +import {Component, Input} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-reservation-expired', + templateUrl: './reservation-expired.component.html' +}) +export class ReservationExpiredComponent { + @Input() + name: string; + + constructor(public activeModal: NgbActiveModal) {} +} diff --git a/frontend/projects/public/src/app/reservation/invoice-form/invoice-form.component.html b/frontend/projects/public/src/app/reservation/invoice-form/invoice-form.component.html new file mode 100644 index 0000000000..66b430ae77 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/invoice-form/invoice-form.component.html @@ -0,0 +1,144 @@ + + +
+
+
+
+ +
+
+ + +
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + + + {{item.name}} ({{item.isoCode}}) + {{item.name}} ({{item.isoCode}}) + + + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
{{form.value.vatCountryCode}}
+ +
+
+
+
+
+ + +
+
+
+ +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+
diff --git a/frontend/projects/public/src/app/reservation/invoice-form/invoice-form.component.ts b/frontend/projects/public/src/app/reservation/invoice-form/invoice-form.component.ts new file mode 100644 index 0000000000..5f521ef334 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/invoice-form/invoice-form.component.ts @@ -0,0 +1,126 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {UntypedFormGroup} from '@angular/forms'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../../shared/i18n.service'; +import {Subscription} from 'rxjs'; +import {LocalizedCountry} from '../../model/localized-country'; +import {PurchaseContext} from '../../model/purchase-context'; +import {InvoicingConfiguration} from '../../model/event'; +import {mobile} from '../../shared/util'; + +@Component({ + selector: 'app-invoice-form', + templateUrl: './invoice-form.component.html' +}) +export class InvoiceFormComponent implements OnInit, OnDestroy { + + @Input() + form: UntypedFormGroup; + + @Input() + purchaseContext?: PurchaseContext; + + @Input() + invoicingConfiguration?: InvoicingConfiguration; + + private langChangeSub: Subscription; + + countries: LocalizedCountry[]; + + taxIdIsRequired = true; + + isMobile = mobile; + + constructor(private translate: TranslateService, private i18nService: I18nService) { } + + ngOnInit(): void { + this.getCountries(this.translate.currentLang); + this.langChangeSub = this.translate.onLangChange.subscribe(change => { + this.getCountries(this.translate.currentLang); + }); + + this.updateItalyEInvoicingFields(); + + this.form.get('italyEInvoicingReferenceType').valueChanges.subscribe(change => { + this.updateItalyEInvoicingFields(); + }); + this.form.get('skipVatNr')?.valueChanges.subscribe(change => { + this.taxIdIsRequired = !change; + }); + } + + public ngOnDestroy(): void { + if (this.langChangeSub) { + this.langChangeSub.unsubscribe(); + } + } + + + updateItalyEInvoicingFields(): void { + const refType = this.form.get('italyEInvoicingReferenceType').value; + if (refType === 'ADDRESSEE_CODE') { + this.form.get('italyEInvoicingReferencePEC').setValue(null); + } else if (refType === 'PEC') { + this.form.get('italyEInvoicingReferenceAddresseeCode').setValue(null); + } else if (refType === 'NONE') { + this.form.get('italyEInvoicingReferencePEC').setValue(null); + this.form.get('italyEInvoicingReferenceAddresseeCode').setValue(null); + } + } + + get addresseeCodeSelected(): boolean { + return this.form.get('italyEInvoicingReferenceType').value === 'ADDRESSEE_CODE'; + } + + get pecSelected(): boolean { + return this.form.get('italyEInvoicingReferenceType').value === 'PEC'; + } + + getCountries(currentLang: string): void { + this.i18nService.getVatCountries(currentLang).subscribe(countries => { + this.countries = countries; + }); + } + + get euVatCheckingEnabled(): boolean { + return this.invoicingConf.euVatCheckingEnabled; + } + + get customerReferenceEnabled(): boolean { + return this.invoicingConf.customerReferenceEnabled; + } + + get invoiceBusiness(): boolean { + return this.form.value.addCompanyBillingDetails; + } + + get vatNumberStrictlyRequired(): boolean { + return this.invoicingConf.vatNumberStrictlyRequired; + } + + get enabledItalyEInvoicing(): boolean { + return this.invoicingConf.enabledItalyEInvoicing; + } + + get italyEInvoicingFormDisplayed(): boolean { + return this.enabledItalyEInvoicing && this.form.value.vatCountryCode === 'IT'; + } + + get countrySelected(): boolean { + return this.form.value.vatCountryCode != null; + } + + private get invoicingConf(): InvoicingConfiguration { + return this.purchaseContext?.invoicingConfiguration || this.invoicingConfiguration; + } + + searchCountry(term: string, country: LocalizedCountry): boolean { + if (term) { + term = term.toLowerCase(); + return country.isoCode.toLowerCase().indexOf(term) > -1 || country.name.toLowerCase().indexOf(term) > -1; + } + return true; + } + + protected readonly mobile = mobile; +} diff --git a/frontend/projects/public/src/app/reservation/modal-remove-subscription/modal-remove-subscription.component.html b/frontend/projects/public/src/app/reservation/modal-remove-subscription/modal-remove-subscription.component.html new file mode 100644 index 0000000000..484ba132a8 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/modal-remove-subscription/modal-remove-subscription.component.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/modal-remove-subscription/modal-remove-subscription.component.ts b/frontend/projects/public/src/app/reservation/modal-remove-subscription/modal-remove-subscription.component.ts new file mode 100644 index 0000000000..a60e89499a --- /dev/null +++ b/frontend/projects/public/src/app/reservation/modal-remove-subscription/modal-remove-subscription.component.ts @@ -0,0 +1,12 @@ +import {Component} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-modal-remove-subscription', + templateUrl: './modal-remove-subscription.component.html' +}) +export class ModalRemoveSubscriptionComponent { + + constructor(public activeModal: NgbActiveModal) { } + +} diff --git a/frontend/projects/public/src/app/reservation/not-found/not-found.component.html b/frontend/projects/public/src/app/reservation/not-found/not-found.component.html new file mode 100644 index 0000000000..8d31ce4876 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/not-found/not-found.component.html @@ -0,0 +1,6 @@ + + +

{{'reservation-page-not-found.reservation-with-id-does-not-exist'|translate: {'0': reservationId|uppercase|slice:0:8} }}

+
+ +
diff --git a/frontend/projects/public/src/app/reservation/not-found/not-found.component.ts b/frontend/projects/public/src/app/reservation/not-found/not-found.component.ts new file mode 100644 index 0000000000..03e02849a6 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/not-found/not-found.component.ts @@ -0,0 +1,36 @@ +import {Component, OnInit} from '@angular/core'; +import {I18nService} from '../../shared/i18n.service'; +import {ActivatedRoute, Router, UrlSerializer} from '@angular/router'; +import {zip} from 'rxjs'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; + +@Component({ + selector: 'app-not-found', + templateUrl: './not-found.component.html' +}) +export class NotFoundComponent implements OnInit { + + private purchaseContextType: PurchaseContextType; + private publicIdentifier: string; + reservationId: string; + purchaseContextUrl: string; + + constructor( + private route: ActivatedRoute, + private router: Router, + private serializer: UrlSerializer, + private purchaseContextService: PurchaseContextService, + private i18nService: I18nService) { } + + ngOnInit() { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + this.purchaseContextType = data.type; + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + this.purchaseContextUrl = this.serializer.serialize(this.router.createUrlTree([this.purchaseContextType, this.publicIdentifier])); + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier).subscribe(ev => { + this.i18nService.setPageTitle('reservation-page-not-found.header.title', ev); + }); + }); + } +} diff --git a/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.html b/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.html new file mode 100644 index 0000000000..3dfc1d06fe --- /dev/null +++ b/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.html @@ -0,0 +1,59 @@ + + +
+ +
+

{{' '}}

+ +
+ + + + + + +

+ + +
  • +

    + +

    +
  • +
  • +
  • +
    + +
      + +
    +
    + +
      + +
    1. +
    2. +
    +
    +
    + + +
    +

    +
    + +
    {{'reservation-page-complete.order-information' | translate: {'0': reservationId, '1': reservationInfo.firstName + ' ' + reservationInfo.lastName} }}
    +
    +
    +
    + +
    +

    +
    +
    +
    + +
    diff --git a/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.scss b/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.scss new file mode 100644 index 0000000000..bdfb00ce8c --- /dev/null +++ b/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.scss @@ -0,0 +1,4 @@ +.bank-account-owner-info { + padding-left: 1em; + margin-bottom: 0; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.ts b/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.ts new file mode 100644 index 0000000000..cfafb8b835 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/offline-payment/offline-payment.component.ts @@ -0,0 +1,78 @@ +import {Component, OnInit} from '@angular/core'; +import {ReservationService} from '../../shared/reservation.service'; +import {ReservationInfo} from '../../model/reservation-info'; +import {ActivatedRoute} from '@angular/router'; +import {zip} from 'rxjs'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../../shared/i18n.service'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {PurchaseContext} from '../../model/purchase-context'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; +import {pollReservationStatus} from '../../shared/util'; + +@Component({ + selector: 'app-offline-payment', + templateUrl: './offline-payment.component.html', + styleUrls: ['./offline-payment.component.scss'] +}) +export class OfflinePaymentComponent implements OnInit { + + reservationInfo: ReservationInfo; + purchaseContextType: PurchaseContextType; + publicIdentifier: string; + reservationId: string; + paymentReason: string; + + purchaseContext: PurchaseContext; + + reservationFinalized: boolean; + + constructor( + private route: ActivatedRoute, + private reservationService: ReservationService, + public translate: TranslateService, + private i18nService: I18nService, + private analytics: AnalyticsService, + private purchaseContextService: PurchaseContextService) { } + + public ngOnInit(): void { + + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + this.purchaseContextType = data.type; + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + zip( + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier), + this.reservationService.getReservationInfo(this.reservationId) + ).subscribe(([ev, reservationInfo]) => { + this.purchaseContext = ev; + this.reservationInfo = reservationInfo; + + this.paymentReason = `${this.reservationInfo.shortId}`; + + this.i18nService.setPageTitle('reservation-page-waiting.header.title', ev); + this.analytics.pageView(ev.analyticsConfiguration); + if (this.reservationInfo.status === 'OFFLINE_FINALIZING') { + this.reservationFinalized = false; + pollReservationStatus(this.reservationId, this.reservationService, res => { + if (res.status === 'DEFERRED_OFFLINE_PAYMENT') { + // redirect to deferred payment. Reload the page + location.reload(); + } + this.reservationInfo = res; + this.reservationFinalized = true; + }); + } else { + this.reservationFinalized = true; + } + }); + }); + } + + get invoiceAvailable(): boolean { + return this.reservationFinalized + && this.purchaseContext.invoicingConfiguration.userCanDownloadReceiptOrInvoice + && this.reservationInfo.invoiceNumber !== null; + } + +} diff --git a/frontend/projects/public/src/app/reservation/overview/overview.component.html b/frontend/projects/public/src/app/reservation/overview/overview.component.html new file mode 100644 index 0000000000..4752b96b23 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/overview/overview.component.html @@ -0,0 +1,143 @@ + + +
    + + + + + +
    + + + + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    {{reservationInfo.billingAddress}}
    +
    {{'invoice.vat' |translate: {'0': ('common.vat' | translate)} }} {{reservationInfo.billingDetails.taxId}}
    +
    +
    +
    {{ taxIdMessageKey | translate}}{{': '}}{{italyEInvoicingFiscalCode}}
    +
    + {{(italyEInvoicingSelectedAddresseeKey | translate) + ': ' + italyEInvoicingReference}} +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    + + +
    +
    +

    +
    +
    + +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    + + + + + + + + +
    + +
    + + +
    + +
    + +
    + {{' '}} + +
    +
    + + +
    + +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    diff --git a/frontend/projects/public/src/app/reservation/overview/overview.component.scss b/frontend/projects/public/src/app/reservation/overview/overview.component.scss new file mode 100644 index 0000000000..95564fc8e1 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/overview/overview.component.scss @@ -0,0 +1,17 @@ +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; + +@include media-breakpoint-up(md) { + .invoice-details { + padding: $table-cell-padding-x; + } + .invoice-details h5 { + font-weight: bold; + font-size: $font-size-base; + } +} + +div.separator { + height: 100%; +} diff --git a/frontend/projects/public/src/app/reservation/overview/overview.component.ts b/frontend/projects/public/src/app/reservation/overview/overview.component.ts new file mode 100644 index 0000000000..822d40aef8 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/overview/overview.component.ts @@ -0,0 +1,406 @@ +import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {ActivatedRoute, NavigationExtras, Router} from '@angular/router'; +import {ReservationService} from '../../shared/reservation.service'; +import {UntypedFormBuilder, UntypedFormGroup} from '@angular/forms'; +import {PaymentMethod, PaymentProxy, PaymentProxyWithParameters} from '../../model/event'; +import {ReservationInfo, SummaryRow} from '../../model/reservation-info'; +import {PaymentProvider, PaymentResult, PaymentStatusNotification, SimplePaymentProvider} from '../../payment/payment-provider'; +import {handleServerSideValidationError} from '../../shared/validation-helper'; +import {I18nService} from '../../shared/i18n.service'; +import {TranslateService} from '@ngx-translate/core'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {ErrorDescriptor, ValidatedResponse} from '../../model/validated-response'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {ReservationExpiredComponent} from '../expired-notification/reservation-expired.component'; +import {zip} from 'rxjs'; +import {PurchaseContext} from '../../model/purchase-context'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; +import {ModalRemoveSubscriptionComponent} from '../modal-remove-subscription/modal-remove-subscription.component'; +import {FeedbackService} from '../../shared/feedback/feedback.service'; +import {SearchParams} from '../../model/search-params'; +import {notifyPaymentErrorToParent} from '../../shared/util'; + +@Component({ + selector: 'app-overview', + templateUrl: './overview.component.html', + styleUrls: ['./overview.component.scss'] +}) +export class OverviewComponent implements OnInit { + + reservationInfo: ReservationInfo; + overviewForm: UntypedFormGroup; + globalErrors: ErrorDescriptor[]; + + private publicIdentifier: string; + private reservationId: string; + purchaseContext: PurchaseContext; + purchaseContextType: PurchaseContextType; + expired: boolean; + + submitting: boolean; + paymentStatusNotification: PaymentStatusNotification; + private forceCheckInProgress = false; + + selectedPaymentProvider: PaymentProvider; + + activePaymentMethods: {[key in PaymentMethod]?: PaymentProxyWithParameters}; + displaySubscriptionForm = false; + + @ViewChild('subscriptionInput') + subscriptionInput: ElementRef; + subscriptionCodeForm: UntypedFormGroup; + + constructor( + private route: ActivatedRoute, + private router: Router, + private reservationService: ReservationService, + private formBuilder: UntypedFormBuilder, + private i18nService: I18nService, + private translate: TranslateService, + private analytics: AnalyticsService, + private modalService: NgbModal, + private purchaseContextService: PurchaseContextService, + private feedbackService: FeedbackService) { } + + ngOnInit() { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + this.purchaseContextType = data.type; + + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier).subscribe(ev => { + this.purchaseContext = ev; + + this.i18nService.setPageTitle('reservation-page.header.title', ev); + + this.loadReservation(); + + this.analytics.pageView(ev.analyticsConfiguration); + }); + }); + + this.subscriptionCodeForm = this.formBuilder.group({ + subscriptionCode: this.formBuilder.control(null) + }); + } + + + loadReservation() { + this.reservationService.getReservationInfo(this.reservationId).subscribe(resInfo => { + this.reservationInfo = resInfo; + + this.activePaymentMethods = this.reservationInfo.activePaymentMethods; + let currentPaymentProxy: PaymentProxy = null; + let selectedPaymentMethod: PaymentMethod = null; + + if (!resInfo.orderSummary.free && this.paymentMethodsCount() === 1) { + selectedPaymentMethod = this.getSinglePaymentMethod(); + currentPaymentProxy = this.reservationInfo.activePaymentMethods[selectedPaymentMethod].paymentProxy; + } + + if (resInfo.orderSummary.free) { + selectedPaymentMethod = 'NONE'; + this.selectedPaymentProvider = new SimplePaymentProvider(); + } + + // + if (this.reservationInfo.tokenAcquired) { + currentPaymentProxy = this.reservationInfo.paymentProxy; + selectedPaymentMethod = this.getPaymentMethodMatchingProxy(currentPaymentProxy); + + // we override and keep only the one selected + const paymentProxyAndParam = this.reservationInfo.activePaymentMethods[selectedPaymentMethod]; + this.activePaymentMethods = {}; + this.activePaymentMethods[selectedPaymentMethod] = paymentProxyAndParam; + // + } else { + this.activePaymentMethods = this.reservationInfo.activePaymentMethods; + } + // + + this.overviewForm = this.formBuilder.group({ + termAndConditionsAccepted: this.reservationInfo.tokenAcquired, + privacyPolicyAccepted: this.reservationInfo.tokenAcquired, + selectedPaymentMethod: selectedPaymentMethod, + paymentProxy: currentPaymentProxy, + gatewayToken: null, + captcha: null + }); + }); + } + + paymentMethodsCount(): number { + return Object.keys(this.activePaymentMethods).length; + } + + private getPaymentMethodMatchingProxy(paymentProxy: PaymentProxy): PaymentMethod | null { + const keys: PaymentMethod[] = Object.keys(this.activePaymentMethods) as PaymentMethod[]; + for (const idx in keys) { + if (this.activePaymentMethods[keys[idx]].paymentProxy === paymentProxy) { + return keys[idx]; + } + } + return null; + } + + getSinglePaymentMethod(): PaymentMethod { + return (Object.keys(this.activePaymentMethods) as PaymentMethod[])[0]; + } + + back(requestInvoice?: boolean): void { + const extras: NavigationExtras = {}; + if (requestInvoice != null) { + extras.queryParams = { + 'requestInvoice': requestInvoice + }; + } + if (this.expired) { + this.reservationService.cancelPendingReservation(this.reservationId).subscribe(res => { + this.router.navigate([this.purchaseContextType, this.publicIdentifier]); + }); + } else { + this.reservationService.backToBooking(this.reservationId).subscribe(res => { + this.router.navigate([this.purchaseContextType, this.publicIdentifier, 'reservation', this.reservationId, 'book'], extras); + }); + } + } + + confirm() { + + if (!this.overviewForm.valid || this.selectedPaymentProvider == null) { + return; // prevent accidental submissions + } + + this.submitting = true; + this.registerUnloadHook(); + this.selectedPaymentProvider.statusNotifications().subscribe(notification => { + if (!this.forceCheckInProgress) { + this.paymentStatusNotification = notification; + } + }); + this.selectedPaymentProvider.pay().subscribe(paymentResult => { + if (paymentResult.success) { + this.overviewForm.get('gatewayToken').setValue(paymentResult.gatewayToken); + const overviewFormValue = this.overviewForm.value; + this.reservationService.confirmOverview(this.reservationId, overviewFormValue, this.translate.currentLang).subscribe(res => { + if (res.success) { + this.unregisterHook(); + if (res.value.redirect) { // handle the case of redirects (e.g. paypal, stripe) + window.location.href = res.value.redirectUrl; + } else { + this.router.navigate([this.purchaseContextType, this.publicIdentifier, 'reservation', this.reservationId, 'success'], { + queryParams: SearchParams.transformParams(this.route.snapshot.queryParams, this.route.snapshot.params) + }); + } + } else { + this.submitting = false; + this.unregisterHook(); + this.globalErrors = handleServerSideValidationError(res, this.overviewForm); + } + }, (err) => { + this.submitting = false; + this.unregisterHook(); + notifyPaymentErrorToParent(this.purchaseContext, this.reservationInfo, this.reservationId, err); + this.globalErrors = handleServerSideValidationError(err, this.overviewForm); + }); + } else { + console.log('paymentResult is not success (may be cancelled)'); + this.unregisterHook(); + if (paymentResult.reservationChanged) { + console.log('reservation status is changed. Trying to reload it...'); + // reload reservation, try to go to /success + this.router.navigate([this.purchaseContextType, this.publicIdentifier, 'reservation', this.reservationId, 'success']); + } else { + this.submitting = false; + } + } + }, (err) => { + this.submitting = false; + this.unregisterHook(); + this.notifyPaymentError(err); + notifyPaymentErrorToParent(this.purchaseContext, this.reservationInfo, this.reservationId, err); + }); + } + + forceCheck(): void { + this.paymentStatusNotification = null; + this.forceCheckInProgress = true; + this.reservationService.forcePaymentStatusCheck(this.reservationId).subscribe(res => { + if (res.success) { + console.log('reservation has been confirmed. Waiting for the PaymentProvider to acknowledge it...'); + } + }, err => { + console.log('error while force-checking', err); + notifyPaymentErrorToParent(this.purchaseContext, this.reservationInfo, this.reservationId, err); + }); + } + + private registerUnloadHook(): void { + window.addEventListener('beforeunload', onUnLoadListener); + console.log('warn on page reload: on'); + } + + private unregisterHook(): void { + window.removeEventListener('beforeunload', onUnLoadListener); + console.log('warn on page reload: off'); + } + + private notifyPaymentError(response: any): void { + const errorDescriptor = new ErrorDescriptor(); + errorDescriptor.fieldName = ''; + if (response != null && response instanceof PaymentResult) { + errorDescriptor.code = 'error.STEP_2_PAYMENT_PROCESSING_ERROR'; + errorDescriptor.arguments = { + '0': (response).reason + }; + } else { + errorDescriptor.code = 'error.STEP_2_PAYMENT_REQUEST_CREATION'; + } + const validatedResponse = new ValidatedResponse(); + validatedResponse.errorCount = 1; + validatedResponse.validationErrors = [errorDescriptor]; + this.globalErrors = handleServerSideValidationError(validatedResponse, this.overviewForm); + } + + get acceptedPrivacyAndTermAndConditions(): boolean { + if (this.purchaseContext.privacyPolicyUrl) { + return this.overviewForm.value.privacyPolicyAccepted && this.overviewForm.value.termAndConditionsAccepted; + } else { + return this.overviewForm.value.termAndConditionsAccepted; + } + } + + handleExpired(expired: boolean) { + setTimeout(() => { + if (!this.expired) { + this.expired = expired; + this.modalService.open(ReservationExpiredComponent, {centered: true, backdrop: 'static'}) + .result.then(() => this.router.navigate([this.purchaseContextType, this.publicIdentifier], {replaceUrl: true})); + } + }); + } + + registerCurrentPaymentProvider(paymentProvider: PaymentProvider) { + this.selectedPaymentProvider = paymentProvider; + } + + clearToken(): void { + this.reservationService.removePaymentToken(this.reservationId).subscribe(r => { + this.loadReservation(); + }); + } + + handleRecaptchaResponse(recaptchaValue: string) { + this.overviewForm.get('captcha').setValue(recaptchaValue); + } + + applySubscription() { + if (!this.subscriptionCodeForm.valid) { + return; + } + const control = this.subscriptionCodeForm.get('subscriptionCode'); + const subscriptionCode = control.value; + this.reservationService.applySubscriptionCode(this.reservationId, subscriptionCode, this.reservationInfo.email).subscribe(res => { + if (res.success) { + this.feedbackService.showSuccess('reservation-page.overview.applied-subscription-code'); + this.loadReservation(); + } else { + // set the first argument as the input + res.validationErrors.forEach(ed => { + ed.arguments = {'0': subscriptionCode}; + }); + control.setErrors({ serverError: res.validationErrors }); + } + }); + } + + removeSubscription(subscriptionRow: SummaryRow) { + this.modalService.open(ModalRemoveSubscriptionComponent, {centered: true, backdrop: 'static'}) + .result.then((res) => { + if (res) { + this.reservationService.removeSubscription(this.reservationId).subscribe(() => { + this.feedbackService.showInfo('reservation-page.overview.removed-subscription'); + this.loadReservation(); + }); + } + }); + } + + toggleSubscriptionFormVisible(): void { + this.displaySubscriptionForm = !this.displaySubscriptionForm; + if (this.displaySubscriptionForm) { + setTimeout(() => this.subscriptionInput.nativeElement.focus(), 200); + } else { + this.subscriptionInput.nativeElement.value = null; + } + } + + get enabledItalyEInvoicing(): boolean { + return this.purchaseContext.invoicingConfiguration.enabledItalyEInvoicing && + this.reservationInfo.billingDetails.invoicingAdditionalInfo.italianEInvoicing != null; + } + + get hasTaxId(): boolean { + return this.reservationInfo.invoiceRequested + && !this.reservationInfo.skipVatNr + && this.reservationInfo.billingDetails.taxId != null; + } + + get italyEInvoicingReference(): string { + const itEInvoicing = this.reservationInfo.billingDetails.invoicingAdditionalInfo.italianEInvoicing; + if (!this.enabledItalyEInvoicing || itEInvoicing == null) { + return ''; + } + return itEInvoicing.reference; + } + + get italyEInvoicingSelectedAddresseeKey(): string { + if (!this.enabledItalyEInvoicing) { + return ''; + } + const referenceType = this.reservationInfo.billingDetails.invoicingAdditionalInfo.italianEInvoicing.referenceType; + return referenceType === 'ADDRESSEE_CODE' ? 'invoice-fields.addressee-code' : 'invoice-fields.pec'; + } + + get italyEInvoicingFiscalCode(): string { + const itEInvoicing = this.reservationInfo.billingDetails.invoicingAdditionalInfo.italianEInvoicing; + if (!this.enabledItalyEInvoicing || itEInvoicing == null) { + return ''; + } + return itEInvoicing.fiscalCode; + } + + get paymentMethodDeferred(): boolean { + if (this.reservationInfo.tokenAcquired) { + return false; + } + return this.selectedPaymentProvider != null && this.selectedPaymentProvider.paymentMethodDeferred; + } + + get appliedSubscription(): boolean { + if (this.reservationInfo && this.reservationInfo.orderSummary && this.reservationInfo.orderSummary.summary) { + return this.reservationInfo.orderSummary.summary.filter((s) => s.type === 'APPLIED_SUBSCRIPTION').length > 0; + } + return false; + } + + get displayRemoveSubscription() { + return this.purchaseContextType === 'event'; + } + + + get taxIdMessageKey(): string { + if (this.reservationInfo.billingDetails.country === 'IT') { + return 'invoice-fields.fiscalCode'; + } + return 'invoice-fields.tax-id'; + } +} + +function onUnLoadListener(e: BeforeUnloadEvent) { + // Cancel the event + e.preventDefault(); + // Chrome requires returnValue to be set + e.returnValue = ''; +} diff --git a/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.component.html b/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.component.html new file mode 100644 index 0000000000..fa32646499 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.component.html @@ -0,0 +1,71 @@ +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +

    + {{ getPaymentMethodDetails(selectedPaymentMethod).labelKey | translate }} +

    +
    + +
    +
    +
    + + + + + + + + + + + + +
    + +
    +
    diff --git a/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.component.ts b/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.component.ts new file mode 100644 index 0000000000..4fbf67e2ad --- /dev/null +++ b/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.component.ts @@ -0,0 +1,68 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {PaymentMethod, PaymentMethodDetails, paymentMethodDetails, PaymentProxy, PaymentProxyWithParameters} from '../../model/event'; +import {PaymentProvider} from '../../payment/payment-provider'; +import {UntypedFormGroup} from '@angular/forms'; +import {ReservationInfo} from '../../model/reservation-info'; +import {PurchaseContext} from '../../model/purchase-context'; + +@Component({ + selector: 'app-payment-method-selector', + templateUrl: './payment-method-selector.component.html', + styleUrls: ['./payment-method-selector.scss'] +}) +export class PaymentMethodSelectorComponent implements OnInit { + + @Input() + purchaseContext: PurchaseContext; + @Input() + reservationInfo: ReservationInfo; + @Input() + overviewForm: UntypedFormGroup; + @Output() + selectedPaymentProvider = new EventEmitter(); + + ngOnInit(): void { + this.overviewForm.get('selectedPaymentMethod').valueChanges.subscribe(v => { + // payment provider has changed, so we must reset the value hold by the container. + this.registerCurrentPaymentProvider(null); + const selectedMethod = this.reservationInfo.activePaymentMethods[v as PaymentMethod]; + this.overviewForm.get('paymentProxy').setValue(selectedMethod.paymentProxy); + }); + } + + get activePaymentMethods(): {[key in PaymentMethod]?: PaymentProxyWithParameters} { + return this.reservationInfo.activePaymentMethods; + } + + get sortedAvailablePaymentMethods(): PaymentMethod[] { + const activeKeys = Object.keys(this.activePaymentMethods); + return Object.keys(paymentMethodDetails) + .filter(pd => activeKeys.includes(pd)) + .map(pd => pd as PaymentMethod); + } + + get activePaymentsCount(): number { + return Object.keys(this.activePaymentMethods).length; + } + + get verticalLayout(): boolean { + return this.activePaymentsCount > 3; + } + + get selectedPaymentMethod(): PaymentMethod { + return this.overviewForm.get('selectedPaymentMethod').value as PaymentMethod; + } + + get selectedPaymentProxy(): PaymentProxy { + return this.overviewForm.get('paymentProxy').value as PaymentProxy; + } + + getPaymentMethodDetails(pm: PaymentMethod): PaymentMethodDetails { + return paymentMethodDetails[pm]; + } + + registerCurrentPaymentProvider(paymentProvider: PaymentProvider) { + this.selectedPaymentProvider.emit(paymentProvider); + } + +} diff --git a/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.scss b/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.scss new file mode 100644 index 0000000000..99db74153c --- /dev/null +++ b/frontend/projects/public/src/app/reservation/payment-method-selector/payment-method-selector.scss @@ -0,0 +1,21 @@ +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; + +.payment-method-selector { + width: 100%; +} + +.payment-method-selector > label { + flex-basis: 100%; + padding:0; + padding-top:6px; + padding-bottom:6px; + font-size: 95%; +} + +@include media-breakpoint-up(md) { + .border-right-md { + border-right: $border-width solid $border-color !important; + } +} diff --git a/frontend/projects/public/src/app/reservation/processing-payment/processing-payment.component.html b/frontend/projects/public/src/app/reservation/processing-payment/processing-payment.component.html new file mode 100644 index 0000000000..735b5553bb --- /dev/null +++ b/frontend/projects/public/src/app/reservation/processing-payment/processing-payment.component.html @@ -0,0 +1,20 @@ + + +
    + + + + + + + +
    +
    +
    {{ (providerWarningVisible ? 'reservation.payment-processing.warning.message' : 'reservation.payment-processing.delay.message') | translate }}
    +
    +
    +
    + +
    diff --git a/frontend/projects/public/src/app/reservation/processing-payment/processing-payment.component.ts b/frontend/projects/public/src/app/reservation/processing-payment/processing-payment.component.ts new file mode 100644 index 0000000000..37d1219c77 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/processing-payment/processing-payment.component.ts @@ -0,0 +1,102 @@ +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {ReservationInfo} from '../../model/reservation-info'; +import {ActivatedRoute, Router} from '@angular/router'; +import {ReservationService} from '../../shared/reservation.service'; +import {zip} from 'rxjs'; +import {I18nService} from '../../shared/i18n.service'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; +import {PurchaseContext} from '../../model/purchase-context'; +import {SearchParams} from '../../model/search-params'; +import {notifyPaymentErrorToParent} from '../../shared/util'; + +@Component({ + selector: 'app-processing-payment', + templateUrl: './processing-payment.component.html' +}) +export class ProcessingPaymentComponent implements OnInit, OnDestroy { + + reservationInfo: ReservationInfo; + purchaseContext: PurchaseContext; + + private purchaseContextType: PurchaseContextType; + private publicIdentifier: string; + private reservationId: string; + forceCheckVisible = false; + providerWarningVisible = false; + private forceCheckInProgress = false; + + private intervalId: any; + + constructor( + private route: ActivatedRoute, + private router: Router, + private reservationService: ReservationService, + private purchaseContextService: PurchaseContextService, + private i18nService: I18nService, + private analytics: AnalyticsService + ) { } + + public ngOnInit(): void { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + this.purchaseContextType = data.type; + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + + zip( + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier), + this.reservationService.getReservationInfo(this.reservationId) + ).subscribe(([ev, reservationInfo]) => { + this.purchaseContext = ev; + this.reservationInfo = reservationInfo; + this.i18nService.setPageTitle('show-ticket.header.title', ev); + this.analytics.pageView(ev.analyticsConfiguration); + }); + + let checkCount = 0; + this.intervalId = setInterval(() => { + const currentStatus = this.reservationInfo.status; + this.reservationService.getReservationStatusInfo(this.reservationId).subscribe(res => { + checkCount++; + if (res.status !== currentStatus) { + clearInterval(this.intervalId); + this.reservationStateChanged(); + } + if ((!this.forceCheckVisible || checkCount > 120) && !this.forceCheckInProgress && checkCount % 10 === 0) { + this.providerWarningVisible = checkCount > 120; + this.forceCheckVisible = !this.providerWarningVisible; + } + }); + }, 2000); + }); + } + private reservationStateChanged() { + // try to navigate to /success. If the reservation is in a different status, the user will be + // redirected accordingly. + this.router.navigate([this.purchaseContextType, this.publicIdentifier, 'reservation', this.reservationId, 'success'], { + queryParams: SearchParams.transformParams(this.route.snapshot.queryParams, this.route.snapshot.queryParams) + }); + } + + public ngOnDestroy() { + clearInterval(this.intervalId); + } + + forceCheck(): void { + this.forceCheckVisible = false; + this.forceCheckInProgress = true; + this.reservationService.forcePaymentStatusCheck(this.reservationId).subscribe(status => { + if (status.redirect) { + window.location.href = status.redirectUrl; + } else if (status.success || status.failure) { + this.reservationStateChanged(); + } + this.forceCheckInProgress = false; + }, err => { + console.log('got error', err); + notifyPaymentErrorToParent(this.purchaseContext, this.reservationInfo, this.reservationId, err); + }); + } + + +} diff --git a/frontend/projects/public/src/app/reservation/release-ticket/release-ticket.component.ts b/frontend/projects/public/src/app/reservation/release-ticket/release-ticket.component.ts new file mode 100644 index 0000000000..a762cf68a9 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/release-ticket/release-ticket.component.ts @@ -0,0 +1,11 @@ +import {Component} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-release-ticket', + templateUrl: './release-ticket.html' +}) +export class ReleaseTicketComponent { + constructor(public activeModal: NgbActiveModal) { + } +} diff --git a/frontend/projects/public/src/app/reservation/release-ticket/release-ticket.html b/frontend/projects/public/src/app/reservation/release-ticket/release-ticket.html new file mode 100644 index 0000000000..33cfbd1e25 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/release-ticket/release-ticket.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/frontend/projects/public/src/app/reservation/reservation.component.html b/frontend/projects/public/src/app/reservation/reservation.component.html new file mode 100644 index 0000000000..864f5743c0 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/reservation.component.html @@ -0,0 +1,8 @@ + +
    +
    +
    +
    +
    +
    diff --git a/frontend/projects/public/src/app/reservation/reservation.component.ts b/frontend/projects/public/src/app/reservation/reservation.component.ts new file mode 100644 index 0000000000..7702151731 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/reservation.component.ts @@ -0,0 +1,40 @@ +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {PurchaseContextService, PurchaseContextType} from '../shared/purchase-context.service'; +import {PurchaseContext} from '../model/purchase-context'; +import {Subscription, zip} from 'rxjs'; + +@Component({ + selector: 'app-reservation', + templateUrl: './reservation.component.html' +}) +export class ReservationComponent implements OnInit, OnDestroy { + + private routerSubscription?: Subscription; + purchaseContext: PurchaseContext; + type: PurchaseContextType; + enableLoginButton = false; + displayFooterLinks = false; + + constructor( + private route: ActivatedRoute, + private purchaseContextService: PurchaseContextService) { } + + ngOnInit() { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + this.purchaseContextService.getContext(data['type'], params[data['publicIdentifierParameter']]).subscribe(purchaseContext => { + this.type = data['type']; + this.purchaseContext = purchaseContext; + }); + }); + this.routerSubscription = this.route.url.subscribe(url => { + const path = url[url.length - 1].path; + this.enableLoginButton = path === 'success'; + this.displayFooterLinks = path === 'book'; + }); + } + + ngOnDestroy(): void { + this.routerSubscription?.unsubscribe(); + } +} diff --git a/frontend/projects/public/src/app/reservation/reservation.guard.ts b/frontend/projects/public/src/app/reservation/reservation.guard.ts new file mode 100644 index 0000000000..c0439d21d3 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/reservation.guard.ts @@ -0,0 +1,80 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router'; +import {Observable, of} from 'rxjs'; +import {catchError, map} from 'rxjs/operators'; +import {ReservationService} from '../shared/reservation.service'; +import {ReservationStatus} from '../model/reservation-info'; +import {SuccessComponent} from './success/success.component'; +import {OverviewComponent} from './overview/overview.component'; +import {BookingComponent} from './booking/booking.component'; +import {OfflinePaymentComponent} from './offline-payment/offline-payment.component'; +import {ProcessingPaymentComponent} from './processing-payment/processing-payment.component'; +import {NotFoundComponent} from './not-found/not-found.component'; +import {ErrorComponent} from './error/error.component'; +import {DeferredOfflinePaymentComponent} from './deferred-offline-payment/deferred-offline-payment.component'; +import {PurchaseContextType} from '../shared/purchase-context.service'; +import {SuccessSubscriptionComponent} from './success-subscription/success-subscription.component'; + +@Injectable({ + providedIn: 'root' +}) +export class ReservationGuard implements CanActivate { + + constructor(private reservationService: ReservationService, private router: Router) { + } + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean { + return this.checkAndRedirect(route.data['type'], route.params[route.data['publicIdentifierParameter']], route.params['reservationId'], route.component); + } + + private checkAndRedirect(type: PurchaseContextType, publicIdentifier: string, reservationId: string, component: any): Observable { + return this.reservationService.getReservationStatusInfo(reservationId) + .pipe(catchError(err => of({ status: 'NOT_FOUND', validatedBookingInformation: false })), map(reservation => { + const selectedComponent = getCorrespondingController(type, reservation.status, reservation.validatedBookingInformation); + if (component === selectedComponent) { + return true; + } + return this.router.createUrlTree(getRouteFromComponent(selectedComponent, type, publicIdentifier, reservationId)); + })); + } +} + +function getRouteFromComponent(component: any, type: PurchaseContextType, publicIdentifier: string, reservationId: string): string[] { + if (component === OverviewComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'overview']; + } else if (component === BookingComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'book']; + } else if (component === SuccessComponent || component === SuccessSubscriptionComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'success']; + } else if (component === OfflinePaymentComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'waiting-payment']; + } else if (component === DeferredOfflinePaymentComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'deferred-payment']; + } else if (component === ProcessingPaymentComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'processing-payment']; + } else if (component === NotFoundComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'not-found']; + } else if (component === ErrorComponent) { + return [type, publicIdentifier, 'reservation', reservationId, 'error']; + } else { + return ['/']; + } +} + +function getCorrespondingController(type: PurchaseContextType, status: ReservationStatus, validatedBookingInformations: boolean) { + switch (status) { + case 'PENDING': return validatedBookingInformations ? OverviewComponent : BookingComponent; + case 'COMPLETE': + case 'FINALIZING': + return type === 'subscription' ? SuccessSubscriptionComponent : SuccessComponent; + case 'OFFLINE_PAYMENT': + case 'OFFLINE_FINALIZING': + return OfflinePaymentComponent; + case 'DEFERRED_OFFLINE_PAYMENT': return DeferredOfflinePaymentComponent; + case 'EXTERNAL_PROCESSING_PAYMENT': + case 'WAITING_EXTERNAL_CONFIRMATION': return ProcessingPaymentComponent; + case 'IN_PAYMENT': + case 'STUCK': return ErrorComponent; + default: return NotFoundComponent; + } +} diff --git a/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.html b/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.html new file mode 100644 index 0000000000..e29bc7fd50 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.html @@ -0,0 +1,102 @@ + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    + +

    + +
    +
    + +

    + {{ 'reservation-page-complete.subscription.usage' | translate:{'0': subscriptionInfo.usageDetails.used} }} +  {{ 'reservation-page-complete.subscription.usage.available' | translate: {'0': subscriptionInfo.usageDetails.available} }} +

    +
    +
    +
    +

    +
    +
    + {{subscriptionInfo.pin}} + +
    +
    +

    +
    + {{subscriptionInfo.id}} + +
    +
    +
    +
    + + +
    + +
    +
    {{ 'reservation-page-complete.subscription.buy-tickets' | translate }}
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    {{'reservation-page-complete.order-information' | translate: {'0': reservationId, '1': reservationInfo.firstName + ' ' + reservationInfo.lastName} }}
    +
    + +
    +
    +
    + +
    diff --git a/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.scss b/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.ts b/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.ts new file mode 100644 index 0000000000..7acb422e92 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/success-subscription/success-subscription.component.ts @@ -0,0 +1,134 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {zip} from 'rxjs'; +import {PurchaseContext} from '../../model/purchase-context'; +import {ReservationInfo, ReservationSubscriptionInfo} from '../../model/reservation-info'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {I18nService} from '../../shared/i18n.service'; +import {PurchaseContextService, PurchaseContextType} from '../../shared/purchase-context.service'; +import {ReservationService} from '../../shared/reservation.service'; +import {TranslateService} from '@ngx-translate/core'; +import {SubscriptionInfo} from '../../model/subscription'; +import {FeedbackService} from '../../shared/feedback/feedback.service'; +import {EventService} from '../../shared/event.service'; +import {BasicEventInfo} from '../../model/basic-event-info'; +import {SearchParams} from '../../model/search-params'; +import {ReservationStatusChanged} from '../../model/embedding-configuration'; +import {embedded, pollReservationStatus} from '../../shared/util'; + +@Component({ + selector: 'app-success-subscription', + templateUrl: './success-subscription.component.html', + styleUrls: ['./success-subscription.component.scss'] +}) +export class SuccessSubscriptionComponent implements OnInit { + + private publicIdentifier: string; + reservationId: string; + private purchaseContextType: PurchaseContextType; + purchaseContext: PurchaseContext; + reservationInfo: ReservationInfo; + compatibleEvents: Array = []; + + reservationFinalized = true; + invoiceReceiptReady = true; + + constructor( + private route: ActivatedRoute, + private purchaseContextService: PurchaseContextService, + private i18nService: I18nService, + private analytics: AnalyticsService, + private reservationService: ReservationService, + private translateService: TranslateService, + private feedbackService: FeedbackService, + private eventService: EventService + ) { } + + ngOnInit(): void { + zip(this.route.data, this.route.params).subscribe(([data, params]) => { + this.publicIdentifier = params[data.publicIdentifierParameter]; + this.reservationId = params['reservationId']; + this.purchaseContextType = data.type; + + this.purchaseContextService.getContext(this.purchaseContextType, this.publicIdentifier).subscribe(ev => { + this.purchaseContext = ev; + this.i18nService.setPageTitle('reservation-page.header.title', ev); + this.loadReservation(); + this.analytics.pageView(ev.analyticsConfiguration); + }); + }); + } + + private loadReservation() { + this.reservationService.getReservationInfo(this.reservationId).subscribe(resInfo => { + this.processReservationInfo(resInfo); + if (!this.reservationFinalized) { + pollReservationStatus(this.reservationId, this.reservationService, res1 => this.processReservationInfo(res1)); + } + }); + } + + private processReservationInfo(resInfo: ReservationInfo) { + const embeddingEnabled = this.purchaseContext.embeddingConfiguration.enabled; + if (embedded && embeddingEnabled) { + window.parent.postMessage( + new ReservationStatusChanged(resInfo.status, this.reservationId), + this.purchaseContext.embeddingConfiguration.notificationOrigin + ); + } + this.reservationInfo = resInfo; + this.reservationFinalized = resInfo.status !== 'FINALIZING'; + this.invoiceReceiptReady = resInfo.metadata.readyForConfirmation; + if (this.reservationFinalized && (!embedded || !embeddingEnabled)) { + this.loadCompatibleEvents(this.subscriptionInfo.id); + } + } + + private loadCompatibleEvents(subscriptionId: string): void { + this.eventService.getEvents(new SearchParams(subscriptionId, null, null, null)).subscribe(events => { + this.compatibleEvents = events; + }); + } + + get purchaseContextTitle(): string { + return this.purchaseContext.title[this.translateService.currentLang]; + } + + get downloadBillingDocumentVisible(): boolean { + return this.purchaseContext.invoicingConfiguration.userCanDownloadReceiptOrInvoice + && this.reservationInfo.paid + && this.reservationInfo.invoiceOrReceiptDocumentPresent; + } + + get subscriptionInfo(): ReservationSubscriptionInfo { + return this.reservationInfo.subscriptionInfos[0]; + } + + get displayPin(): boolean { + if (this.subscriptionInfo.configuration != null) { + return this.reservationFinalized && this.subscriptionInfo.configuration.displayPin; + } + return this.reservationFinalized; // by default, we display PIN + } + + public reSendReservationEmail(): void { + this.reservationService.reSendReservationEmail('subscription', this.publicIdentifier, this.reservationId, this.i18nService.getCurrentLang()).subscribe(() => { + this.feedbackService.showSuccess('email.confirmation-email-sent'); + }); + } + + get subscription(): SubscriptionInfo { + return this.purchaseContext as SubscriptionInfo; + } + + public copied(payload: string): void { + this.feedbackService.showSuccess('reservation-page-complete.subscription.copy.success'); + } + + get showReservationButtons(): boolean { + return this.reservationFinalized + && (!embedded || !this.purchaseContext.embeddingConfiguration.enabled) + && !this.reservationInfo.metadata.hideConfirmationButtons; + } + +} diff --git a/frontend/projects/public/src/app/reservation/success/success.component.html b/frontend/projects/public/src/app/reservation/success/success.component.html new file mode 100644 index 0000000000..71572b7229 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/success/success.component.html @@ -0,0 +1,118 @@ + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    + +

    +
    + +
    +
    +
    +

    {{'reservation-page-complete.ticket-nr' | translate}} - {{tc.name}}

    +

    {{ticket.fullName}}

    +

    {{'reservation-page-complete.ticket-not-assigned' | translate }}

    +
    + +
    +
    + +
    + + {{'reservation-page-complete.download-ticket'|translate}} +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    {{'reservation-page-complete.order-information' | translate: {'0': reservationId, '1': reservationInfo.firstName + ' ' + reservationInfo.lastName} }}
    +
    + +
    +
    +
    + +
    diff --git a/frontend/projects/public/src/app/reservation/success/success.component.scss b/frontend/projects/public/src/app/reservation/success/success.component.scss new file mode 100644 index 0000000000..3cad39009b --- /dev/null +++ b/frontend/projects/public/src/app/reservation/success/success.component.scss @@ -0,0 +1,19 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; + +p.ticket-info { + padding: 15px; + margin-top: 10px; +} + +.bg-info { + background-color: #d9edf7!important; +} + +.sticky { + position: -webkit-sticky; + position: sticky; + bottom: 0px; + left: 0px; + z-index: 200; +} diff --git a/frontend/projects/public/src/app/reservation/success/success.component.ts b/frontend/projects/public/src/app/reservation/success/success.component.ts new file mode 100644 index 0000000000..54d914959c --- /dev/null +++ b/frontend/projects/public/src/app/reservation/success/success.component.ts @@ -0,0 +1,188 @@ +import {Component, OnInit} from '@angular/core'; +import {ReservationService} from '../../shared/reservation.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {Event} from '../../model/event'; +import {EventService} from '../../shared/event.service'; +import {TicketService} from '../../shared/ticket.service'; +import {Ticket} from '../../model/ticket'; +import {ReservationInfo, TicketsByTicketCategory} from '../../model/reservation-info'; +import {I18nService} from '../../shared/i18n.service'; +import {AnalyticsService} from '../../shared/analytics.service'; +import {handleServerSideValidationError} from '../../shared/validation-helper'; +import {UntypedFormGroup} from '@angular/forms'; +import {TranslateService} from '@ngx-translate/core'; +import {InfoService} from '../../shared/info.service'; +import {first} from 'rxjs/operators'; +import {WalletConfiguration} from '../../model/info'; +import {ReservationStatusChanged} from '../../model/embedding-configuration'; +import {embedded, pollReservationStatus} from '../../shared/util'; + +@Component({ + selector: 'app-success', + templateUrl: './success.component.html', + styleUrls: ['./success.component.scss'] +}) +export class SuccessComponent implements OnInit { + + reservationInfo: ReservationInfo; + eventShortName: string; + reservationId: string; + + event: Event; + + reservationMailSent = false; + sendEmailForTicketStatus: {[key: string]: boolean} = {}; + ticketsFormControl: {[key: string]: UntypedFormGroup} = {}; + ticketsFormShow: {[key: string]: boolean} = {}; + ticketsReleaseShow: {[key: string]: boolean} = {}; + + unlockedTicketCount = 0; + ticketsAllAssigned = true; + reservationFinalized = true; + invoiceReceiptReady = true; + private walletConfiguration: WalletConfiguration; + + constructor( + private route: ActivatedRoute, + private reservationService: ReservationService, + private eventService: EventService, + private ticketService: TicketService, + private i18nService: I18nService, + private analytics: AnalyticsService, + private router: Router, + private translateService: TranslateService, + private infoService: InfoService) { } + + public ngOnInit(): void { + this.route.params.subscribe(params => { + this.eventShortName = params['eventShortName']; + this.reservationId = params['reservationId']; + this.infoService.getInfo().pipe(first()) + .subscribe(info => this.walletConfiguration = info.walletConfiguration); + this.eventService.getEvent(this.eventShortName).subscribe(ev => { + this.event = ev; + this.i18nService.setPageTitle('reservation-page-complete.header.title', ev); + this.analytics.pageView(ev.analyticsConfiguration); + }); + this.loadReservation(); + }); + } + + private loadReservation(): void { + this.reservationService.getReservationInfo(this.reservationId).subscribe(res => { + this.processReservationInfo(res); + if (!this.reservationFinalized) { + pollReservationStatus(this.reservationId, this.reservationService, res1 => this.processReservationInfo(res1)); + } + }); + } + + private processReservationInfo(res: ReservationInfo) { + if (embedded && this.event.embeddingConfiguration.enabled) { + window.parent.postMessage( + new ReservationStatusChanged(res.status, this.reservationId), + this.event.embeddingConfiguration.notificationOrigin + ); + } + this.reservationInfo = res; + // + this.reservationFinalized = res.status !== 'FINALIZING'; + this.ticketsAllAssigned = res.status !== 'FINALIZING'; + this.invoiceReceiptReady = res.metadata.readyForConfirmation; + this.unlockedTicketCount = 0; + // + res.ticketsByCategory.forEach((tc) => { + tc.tickets.forEach((ticket: Ticket) => { + this.buildFormControl(ticket); + if (!ticket.locked) { + this.unlockedTicketCount += 1; + } + this.ticketsAllAssigned = this.ticketsAllAssigned && ticket.assigned; + }); + }); + } + + private buildFormControl(ticket: Ticket): void { + this.ticketsFormControl[ticket.uuid] = this.ticketService.buildFormGroupForTicket(ticket); + } + + sendEmailForTicket(ticketIdentifier: string): void { + this.ticketService.sendTicketByEmail(this.eventShortName, ticketIdentifier).subscribe(res => { + if (res) { + this.sendEmailForTicketStatus[ticketIdentifier] = true; + } + }); + } + + reSendReservationEmail(): void { + this.reservationService.reSendReservationEmail('event', this.eventShortName, this.reservationId, this.i18nService.getCurrentLang()).subscribe(res => { + this.reservationMailSent = res; + }); + } + + updateTicket(uuid: string): void { + const ticketValue = this.ticketsFormControl[uuid].value; + this.ticketService.updateTicket(this.event.shortName, uuid, ticketValue).subscribe(res => { + if (res.success) { + this.loadReservation(); + this.hideTicketForm(uuid); + } + }, (err) => { + handleServerSideValidationError(err, this.ticketsFormControl[uuid]); + }); + } + + releaseTicket(ticket: Ticket) { + this.ticketService.openReleaseTicket(ticket, this.event.shortName) + .subscribe(released => { + if (released) { + const singleTicket = this.reservationInfo.ticketsByCategory.map((c) => c.tickets.length).reduce((c1, c2) => c1 + c2) === 1; + if (singleTicket) { + this.router.navigate(['event', this.event.shortName], {replaceUrl: true}); + } else { + this.loadReservation(); + } + } + }); + } + + get ticketFormVisible(): boolean { + return Object.keys(this.ticketsFormShow).length > 0; + } + + hideTicketForm(uuid: string): void { + delete this.ticketsFormShow[uuid]; + } + + get downloadBillingDocumentVisible(): boolean { + return this.invoiceReceiptReady + && this.event.invoicingConfiguration.userCanDownloadReceiptOrInvoice + && this.reservationInfo.paid + && this.reservationInfo.invoiceOrReceiptDocumentPresent; + } + + public isOnlineTicket(category: TicketsByTicketCategory): boolean { + return this.event.format === 'ONLINE' + || (this.event.format === 'HYBRID' && category.ticketAccessType === 'ONLINE'); + } + + get purchaseContextTitle(): string { + return this.event.title[this.translateService.currentLang]; + } + + get showReservationButtons(): boolean { + return this.reservationFinalized + && (!embedded || !this.event.embeddingConfiguration.enabled) + && !this.reservationInfo.metadata.hideConfirmationButtons; + } + + get walletIntegrationEnabled(): boolean { + return this.walletConfiguration != null && + (this.walletConfiguration.gWalletEnabled || this.walletConfiguration.passEnabled); + } + + downloadTicket(ticket: Ticket): void { + this.ticketService.openDownloadTicket(ticket, this.eventShortName, this.walletConfiguration) + .subscribe(() => {}); + } +} diff --git a/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.html b/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.html new file mode 100644 index 0000000000..7d22345722 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + {{'summary.table.subscription'|translate: {'0': isSubscriptionPurchaseContext ? purchaseContext.title[currentLang] : summaryRow.name } }} + + + + + + {{'reservation-page.vat'|translate:{'0': summaryRow.taxPercentage, '1': ('common.vat' | translate)} }} + + {{summaryRow.name}} + {{summaryRow.amount}}{{summaryRow.price}}
    {{'reservation-page.vat'|translate:{'0': purchaseContext.vat, '1': ('common.vat' | translate)} }}
    *
    {{'reservation-page.vat-included'|translate: {'0': purchaseContext.vat, '1': ('common.vat' | translate)} }}
    {{'invoice.vat-voided'|translate: {'0': ('common.vat' | translate)} }}
    * {{'invoice.vat-not-added'|translate: {'0': ('common.vat' | translate)} }}
    diff --git a/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.scss b/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.scss new file mode 100644 index 0000000000..852ce54f4a --- /dev/null +++ b/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.scss @@ -0,0 +1,7 @@ +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; + +.delete-button { + color: $gray-600; +} diff --git a/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.ts b/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.ts new file mode 100644 index 0000000000..08b6f35e25 --- /dev/null +++ b/frontend/projects/public/src/app/reservation/summary-table/summary-table.component.ts @@ -0,0 +1,45 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {ReservationInfo, SummaryRow} from '../../model/reservation-info'; +import {PurchaseContext} from '../../model/purchase-context'; +import {PurchaseContextType} from '../../shared/purchase-context.service'; +import {TranslateService} from '@ngx-translate/core'; + +@Component({ + selector: 'app-summary-table', + templateUrl: './summary-table.component.html', + styleUrls: ['./summary-table.component.scss'] +}) +export class SummaryTableComponent { + + @Input() + reservationInfo: ReservationInfo; + + @Input() + purchaseContext: PurchaseContext; + + @Input() + displayRemoveSubscription: boolean; + + @Input() + purchaseContextType: PurchaseContextType; + + @Output() + removeSubscription: EventEmitter = new EventEmitter(); + + constructor(private translateService: TranslateService) { + } + + get currentLang(): string { + return this.translateService.currentLang; + } + + get isSubscriptionPurchaseContext(): boolean { + return this.purchaseContextType === 'subscription'; + } + + get displaySplitPaymentNote(): boolean { + return !this.reservationInfo.orderSummary.free + && this.reservationInfo.billingDetails.invoicingAdditionalInfo?.italianEInvoicing?.splitPayment; + } + +} diff --git a/frontend/projects/public/src/app/reservation/ticket-form/ticket-form.component.html b/frontend/projects/public/src/app/reservation/ticket-form/ticket-form.component.html new file mode 100644 index 0000000000..fb7642468f --- /dev/null +++ b/frontend/projects/public/src/app/reservation/ticket-form/ticket-form.component.html @@ -0,0 +1,49 @@ +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + +
    diff --git a/frontend/projects/public/src/app/reservation/ticket-form/ticket-form.component.ts b/frontend/projects/public/src/app/reservation/ticket-form/ticket-form.component.ts new file mode 100644 index 0000000000..9088ac79fa --- /dev/null +++ b/frontend/projects/public/src/app/reservation/ticket-form/ticket-form.component.ts @@ -0,0 +1,40 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {UntypedFormGroup} from '@angular/forms'; +import {Ticket} from '../../model/ticket'; +import {PurchaseContext} from '../../model/purchase-context'; +import {ReservationMetadata} from '../../model/reservation-info'; + +@Component({ + selector: 'app-ticket-form', + templateUrl: './ticket-form.component.html' +}) +export class TicketFormComponent implements OnInit { + + @Input() + form: UntypedFormGroup; + + @Input() + ticket: Ticket; + + @Input() + purchaseContext: PurchaseContext; + + @Input() + reservationMetadata: ReservationMetadata; + + constructor() { } + + public ngOnInit(): void { + if (this.form && this.purchaseContext && this.purchaseContext.contentLanguages && this.purchaseContext.contentLanguages.length === 1) { + this.form.get('userLanguage').setValue(this.purchaseContext.contentLanguages[0].locale); + } + } + + getAdditional(form: UntypedFormGroup) { + return form.get('additional') as UntypedFormGroup; + } + + get emailEditForbidden(): boolean { + return this.ticket.locked || (this.reservationMetadata?.lockEmailEdit && this.ticket.email != null); + } +} diff --git a/frontend/projects/public/src/app/shared/analytics.service.ts b/frontend/projects/public/src/app/shared/analytics.service.ts new file mode 100644 index 0000000000..9ea402e047 --- /dev/null +++ b/frontend/projects/public/src/app/shared/analytics.service.ts @@ -0,0 +1,55 @@ +import {Injectable} from '@angular/core'; +import {AnalyticsConfiguration} from '../model/analytics-configuration'; +import {Observable} from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class AnalyticsService { + + private gaScript: Observable<[Function, AnalyticsConfiguration, string]> = null; + + constructor() { + } + + pageView(conf: AnalyticsConfiguration): void { + const locationPathName = location.pathname; + if (conf.googleAnalyticsKey) { + this.handleGoogleAnalytics(conf, locationPathName); + } + } + + + private handleGoogleAnalytics(conf: AnalyticsConfiguration, locationPathName: string) { + if (this.gaScript === null) { + this.gaScript = new Observable<[Function, AnalyticsConfiguration, string]>(subscribe => { + if (!document.getElementById('GA_SCRIPT')) { // <- script is not created + const scriptElem = document.createElement('script'); + scriptElem.id = 'GA_SCRIPT'; + scriptElem.addEventListener('load', () => { + subscribe.next([window['ga'], conf, locationPathName]); + }); + scriptElem.src = 'https://ssl.google-analytics.com/analytics.js'; + scriptElem.async = true; + scriptElem.defer = true; + document.body.appendChild(scriptElem); + } else if (!window['ga']) { // <- script has been created, but not loaded + document.getElementById('GA_SCRIPT').addEventListener('load', () => { + subscribe.next([window['ga'], conf, locationPathName]); + }); + } else { // <- script has been loaded + subscribe.next([window['ga'], conf, locationPathName]); + } + }); + } + + this.gaScript.subscribe(([ga, configuration, pathname]) => { + if (configuration.googleAnalyticsScrambledInfo) { + ga('create', configuration.googleAnalyticsKey, {'anonymizeIp': true, 'storage': 'none', 'clientId': configuration.clientId}); + } else { + ga('create', configuration.googleAnalyticsKey); + } + ga('send', 'pageview', pathname); + }); + } +} diff --git a/frontend/projects/public/src/app/shared/clipboard-copy/clipboard-copy.directive.ts b/frontend/projects/public/src/app/shared/clipboard-copy/clipboard-copy.directive.ts new file mode 100644 index 0000000000..ac0ebae1ba --- /dev/null +++ b/frontend/projects/public/src/app/shared/clipboard-copy/clipboard-copy.directive.ts @@ -0,0 +1,35 @@ +import {Directive, EventEmitter, HostListener, Input, Output} from '@angular/core'; + +/** + * Based upon https://stackoverflow.com/a/52949299/9679084 + */ +@Directive({ selector: '[appClipboardCopy]' }) +export class ClipboardCopyDirective { + + // tslint:disable-next-line:no-input-rename + @Input('appClipboardCopy') + public payload: string; + + @Output() + public copied: EventEmitter = new EventEmitter(); + + @HostListener('click', ['$event']) + public onClick(event: MouseEvent): void { + + event.preventDefault(); + if (!this.payload) { + return; + } + + const listener = (e: ClipboardEvent) => { + const clipboard = e.clipboardData || window['clipboardData']; + clipboard.setData('text', this.payload.toString()); + e.preventDefault(); + this.copied.emit(this.payload); + }; + + document.addEventListener('copy', listener, false); + document.execCommand('copy'); + document.removeEventListener('copy', listener, false); + } +} diff --git a/frontend/projects/public/src/app/shared/custom-css-helper.ts b/frontend/projects/public/src/app/shared/custom-css-helper.ts new file mode 100644 index 0000000000..e739119088 --- /dev/null +++ b/frontend/projects/public/src/app/shared/custom-css-helper.ts @@ -0,0 +1,31 @@ +import {Event} from '../model/event'; + +export function removeAllCustomEventCss() { + document.head.querySelectorAll('style[data-event-custom-css]').forEach(e => e.remove()); +} + +export function handleCustomCss(event: Event): void { + if (event.customCss === null) { + //remove all custom event styles, as this event does not have any override + removeAllCustomEventCss(); + } else { + const id = 'event-custom-css-' + event.organizationName + '-' + event.shortName; + const a = document.getElementById('event-custom-css-' + event.organizationName + '-' + event.shortName); + const found = document.head.querySelectorAll('style[data-event-custom-css]'); + + //remove all custom event styles already present that don't have the expected id + found.forEach(e => { + if (e.id !== id) {e.remove()} + }); + + //create custom css + if (a === null) { + const style = document.createElement('style'); + style.setAttribute('id', id); + style.setAttribute('type', 'text/css') + style.setAttribute('data-event-custom-css', 'true'); + style.textContent = event.customCss; + document.head.appendChild(style) + } + } +} diff --git a/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.html b/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.html new file mode 100644 index 0000000000..5dca94b78e --- /dev/null +++ b/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.html @@ -0,0 +1,9 @@ + +
    +
    + +
    +
    +

    {{ title }}

    +
    +
    diff --git a/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.scss b/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.scss new file mode 100644 index 0000000000..58a9013ac8 --- /dev/null +++ b/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.scss @@ -0,0 +1,11 @@ +.img-responsive { + max-height: 100px; + margin: auto; + display: block; + max-width: 100%; + height: auto; +} + +h1 { + margin-top:20px; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.ts b/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.ts new file mode 100644 index 0000000000..aed2dfc4ae --- /dev/null +++ b/frontend/projects/public/src/app/shared/event-header/purchase-context-header.component.ts @@ -0,0 +1,81 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {I18nService} from '../i18n.service'; +import {removeDOMNode} from '../event.service'; +import {PurchaseContext} from '../../model/purchase-context'; +import {Event} from '../../model/event'; +import {PurchaseContextType} from '../purchase-context.service'; +import {TranslateService} from '@ngx-translate/core'; + +@Component({ + selector: 'app-purchase-context-header', + templateUrl: './purchase-context-header.component.html', + styleUrls: ['./purchase-context-header.component.scss'] +}) +export class PurchaseContextHeaderComponent implements OnInit, OnDestroy { + + @Input() + purchaseContext: PurchaseContext; + + @Input() + type: PurchaseContextType; + + @Input() + displayTopLoginButton = true; + + schemaElem: HTMLScriptElement; + + constructor(private i18nService: I18nService, private translateService: TranslateService) { + } + + ngOnInit() { + // https://developers.google.com/search/docs/data-types/event + // https://search.google.com/test/rich-results?utm_campaign=devsite&utm_medium=jsonld&utm_source=event&id=tqxuXf4XIb4xolzr7EiE2Q + + if (this.type === 'event') { + + const ev = this.purchaseContext as Event; + const start = new Date(ev.datesWithOffset.startDateTime); + const end = new Date(ev.datesWithOffset.endDateTime); + const descriptionHolder = document.createElement('div'); + descriptionHolder.innerHTML = ev.description[this.i18nService.getCurrentLang()]; + + const jsonSchema = { + '@context': 'https://schema.org', + '@type': 'Event', + 'name' : ev.title[this.i18nService.getCurrentLang()], + 'startDate': start.toISOString(), + 'endDate': end.toISOString(), + 'description': descriptionHolder.innerText.trim(), + 'location': { + '@type': 'Place', + 'address': ev.location + }, + 'organizer': { + '@type': 'Organization', + 'name': ev.organizationName, + 'email': ev.organizationEmail + }, + 'image': '/file/' + ev.fileBlobId + }; + + this.schemaElem = document.createElement('script'); + this.schemaElem.text = JSON.stringify(jsonSchema); + this.schemaElem.type = 'application/ld+json'; + document.head.appendChild(this.schemaElem); + } + } + + get title(): string { + return this.purchaseContext.title[this.translateService.currentLang]; + } + + get isEvent(): boolean { + return this.type === 'event'; + } + + ngOnDestroy() { + if (this.type === 'event') { + removeDOMNode(this.schemaElem); + } + } +} diff --git a/frontend/projects/public/src/app/shared/event.service.ts b/frontend/projects/public/src/app/shared/event.service.ts new file mode 100644 index 0000000000..19c7b53057 --- /dev/null +++ b/frontend/projects/public/src/app/shared/event.service.ts @@ -0,0 +1,92 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {Observable, of} from 'rxjs'; +import {BasicEventInfo} from '../model/basic-event-info'; +import {Event} from '../model/event'; +import {ItemsByCategory} from '../model/items-by-category'; +import {WaitingListSubscriptionRequest} from '../model/waiting-list-subscription-request'; +import {ValidatedResponse} from '../model/validated-response'; +import {shareReplay} from 'rxjs/operators'; +import {EventCode} from '../model/event-code'; +import {DateValidity} from '../model/date-validity'; +import {SearchParams} from '../model/search-params'; + +@Injectable({ + providedIn: 'root' +}) +export class EventService { + + private eventCache: {[key: string]: Observable} = {}; + + constructor(private http: HttpClient) { } + + getEvents(searchParams?: SearchParams): Observable { + const params = searchParams?.toHttpParams(); + return this.http.get('/api/v2/public/events', { + responseType: 'json', + params + }); + } + + getEvent(eventShortName: string): Observable { + // caching as explained with https://blog.angularindepth.com/fastest-way-to-cache-for-lazy-developers-angular-with-rxjs-444a198ed6a6 + if (!this.eventCache[eventShortName]) { + const preloadEvent = document.getElementById('preload-event'); + if (preloadEvent && preloadEvent.getAttribute('data-param') === eventShortName) { + this.eventCache[eventShortName] = of(JSON.parse(preloadEvent.textContent)).pipe(shareReplay(1)); + } else { + this.eventCache[eventShortName] = this.http.get(`/api/v2/public/event/${eventShortName}`).pipe(shareReplay(1)); + } + setTimeout(() => { + delete this.eventCache[eventShortName]; + }, 60000 * 20); // clean up cache after 20 minutes + } + + return this.eventCache[eventShortName]; + } + + getEventTicketsInfo(eventShortName: string, code?: string): Observable { + const params = code ? {params: {code: code}} : {}; + return this.http.get(`/api/v2/public/event/${eventShortName}/ticket-categories`, params); + } + + submitWaitingListSubscriptionRequest(eventShortName: string, waitingListSubscriptionRequest: WaitingListSubscriptionRequest): Observable> { + return this.http.post>(`/api/v2/public/event/${eventShortName}/waiting-list/subscribe`, waitingListSubscriptionRequest); + } + + validateCode(eventShortName: string, code: string): Observable> { + return this.http.get>(`/api/v2/public/event/${eventShortName}/validate-code`, {params: {code: code}}); + } +} + +export function shouldDisplayTimeZoneInfo(provider: DateValidity): boolean { + const datesWithOffset = provider.datesWithOffset; + return isDifferentTimeZone(datesWithOffset.startDateTime, datesWithOffset.startTimeZoneOffset) + || isDifferentTimeZone(datesWithOffset.endDateTime, datesWithOffset.endTimeZoneOffset); +} + +export function isDifferentTimeZone(serverTs: number, serverOffset: number): boolean { + // client: + // The time-zone offset is the difference, in minutes, from local time to UTC. + // Note that this means that the offset is positive if the local timezone is behind UTC and negative if it is ahead. + // source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + // + // server: + // nothing special, the offset is returned as it should be (positive if ahead of UTC, negative otherwise), in seconds + + const clientOffset = new Date(serverTs).getTimezoneOffset() * 60; + return (clientOffset + serverOffset) !== 0; +} + +/** + * This is a polyfill for Node.remove(), which is not supported in IE + * @param node the Node to remove + * @returns true if the Node has been removed, false otherwise + */ +export function removeDOMNode(node: Node): boolean { + if (node != null && node.parentNode != null) { + node.parentNode.removeChild(node); + return true; + } + return false; +} diff --git a/frontend/projects/public/src/app/shared/feedback/feedback.component.html b/frontend/projects/public/src/app/shared/feedback/feedback.component.html new file mode 100644 index 0000000000..9b62bb3505 --- /dev/null +++ b/frontend/projects/public/src/app/shared/feedback/feedback.component.html @@ -0,0 +1,10 @@ + +
    +
    + +
    +
    + {{text | translate}} +
    +
    +
    diff --git a/frontend/projects/public/src/app/shared/feedback/feedback.component.scss b/frontend/projects/public/src/app/shared/feedback/feedback.component.scss new file mode 100644 index 0000000000..61167096a4 --- /dev/null +++ b/frontend/projects/public/src/app/shared/feedback/feedback.component.scss @@ -0,0 +1,34 @@ +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/variables"; + +:host ::ng-deep .toast { + + @include media-breakpoint-down(lg) { + position: fixed; + top: 0; + left: 0; + margin: 2em; + max-width: unset; + background-color: white; + } + + @include media-breakpoint-up(lg) { + position: fixed; + bottom: 20px; + right: 0; + margin: 2rem; + } + + padding: 0; + z-index: 101; + + .toast-body { + padding: 0; + } +} + +.message { + padding: 1rem; + font-size: $font-size-base * 1.1; +} diff --git a/frontend/projects/public/src/app/shared/feedback/feedback.component.ts b/frontend/projects/public/src/app/shared/feedback/feedback.component.ts new file mode 100644 index 0000000000..d143fbdaf3 --- /dev/null +++ b/frontend/projects/public/src/app/shared/feedback/feedback.component.ts @@ -0,0 +1,62 @@ +import {Component} from '@angular/core'; +import {FeedbackService} from './feedback.service'; +import {FeedbackType} from '../../model/feedback'; +import {IconProp} from '@fortawesome/fontawesome-svg-core'; + + +@Component({ + selector: 'app-feedback', + templateUrl: './feedback.component.html', + styleUrls: ['./feedback.component.scss'] +}) +export class FeedbackComponent { + text: string; + active: boolean; + private type: FeedbackType; + + constructor(private feedbackService: FeedbackService) { + this.feedbackService.displayNotification().subscribe(details => { + this.active = details.active; + this.text = details.message; + this.type = details.type || 'INFO'; + }); + } + + public hide(): void { + this.active = false; + } + + get boxClass(): string { + switch (this.type) { + case 'SUCCESS': + return 'border-success text-success'; + case 'ERROR': + return 'border-danger text-danger'; + case 'INFO': + return 'border-primary text-primary'; + } + } + + get headerClass(): string { + switch (this.type) { + case 'SUCCESS': + return 'bg-success text-white'; + case 'ERROR': + return 'bg-danger text-white'; + case 'INFO': + return 'bg-white text-primary'; + } + } + + get boxIcon(): IconProp { + switch (this.type) { + case 'SUCCESS': + return ['far', 'check-circle']; + case 'ERROR': + return ['fas', 'exclamation-circle']; + case 'INFO': + return ['fas', 'info-circle']; + } + } + +} diff --git a/frontend/projects/public/src/app/shared/feedback/feedback.service.ts b/frontend/projects/public/src/app/shared/feedback/feedback.service.ts new file mode 100644 index 0000000000..2450c0fa41 --- /dev/null +++ b/frontend/projects/public/src/app/shared/feedback/feedback.service.ts @@ -0,0 +1,44 @@ +import {Injectable} from '@angular/core'; +import {Observable, Subject} from 'rxjs'; +import {FeedbackContent} from '../../model/feedback'; + +@Injectable({ + providedIn: 'root' +}) +export class FeedbackService { + + private toastSubject = new Subject(); + + public showSuccess(message: string) { + this.toastSubject.next({ + active: true, + message, + type: 'SUCCESS' + }); + } + + public showError(message: string) { + this.toastSubject.next({ + active: true, + message, + type: 'ERROR' + }); + } + + public showInfo(message: string) { + this.toastSubject.next({ + active: true, + message, + type: 'INFO' + }); + } + + public hide() { + this.toastSubject.next({ active: false }); + } + + public displayNotification(): Observable { + return this.toastSubject; + } + +} diff --git a/frontend/projects/public/src/app/shared/i18n.service.ts b/frontend/projects/public/src/app/shared/i18n.service.ts new file mode 100644 index 0000000000..37405565c3 --- /dev/null +++ b/frontend/projects/public/src/app/shared/i18n.service.ts @@ -0,0 +1,131 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable, of, zip } from 'rxjs'; +import { Language } from '../model/event'; +import { LocalizedCountry } from '../model/localized-country'; +import { Title } from '@angular/platform-browser'; +import {TranslateService, TranslateLoader, LangChangeEvent} from '@ngx-translate/core'; +import { Router, NavigationStart } from '@angular/router'; +import { map, mergeMap, shareReplay, catchError } from 'rxjs/operators'; +import { EventService } from './event.service'; +import { PurchaseContextType } from './purchase-context.service'; +import {PurchaseContext} from '../model/purchase-context'; +import {getFromSessionStorage, writeToSessionStorage} from './util'; + +@Injectable({ + providedIn: 'root' +}) +export class I18nService { + + + private applicationLanguages: Observable; + + private static getInterpolateParams(lang: string, ctx: PurchaseContext): any { + if (ctx != null) { + return {'0': ctx.title[lang]}; + } + return null; + } + + constructor( + private http: HttpClient, + private title: Title, + private translateService: TranslateService, + private router: Router, + private customLoader: CustomLoader, + private eventService: EventService) { } + + getCountries(locale: string): Observable { + return this.http.get(`/api/v2/public/i18n/countries/${locale}`); + } + + getVatCountries(locale: string): Observable { + return this.http.get(`/api/v2/public/i18n/countries-vat/${locale}`); + } + + getEUVatCountries(locale: string): Observable { + return this.http.get(`/api/v2/public/i18n/eu-countries-vat/${locale}`); + } + + getAvailableLanguages(): Observable { + if (!this.applicationLanguages) { + this.applicationLanguages = this.http.get(`/api/v2/public/i18n/languages`).pipe(shareReplay(1)); + } + return this.applicationLanguages; + } + + setPageTitle(titleCode: string, ctx?: PurchaseContext): void { + + const titleSub = this.translateService.onLangChange.subscribe((params: LangChangeEvent) => { + this.title.setTitle(this.translateService.instant(titleCode, I18nService.getInterpolateParams(params.lang, ctx))); + }); + + const routerSub = this.router.events.subscribe(ev => { + if (ev instanceof NavigationStart) { + routerSub.unsubscribe(); + titleSub.unsubscribe(); + this.title.setTitle(null); + } + }); + + this.title.setTitle(this.translateService.instant(titleCode, I18nService.getInterpolateParams(this.translateService.currentLang, ctx))); + } + + persistLanguage(lang: string): void { + writeToSessionStorage('ALFIO_LANG', lang); + } + + getPersistedLanguage(): string { + return getFromSessionStorage('ALFIO_LANG'); + } + + getCurrentLang(): string { + return this.translateService.currentLang; + } + + useTranslation(type: PurchaseContextType, publicIdentifier: string, lang: string): Observable { + const overrideBundle = this.getOverrideBundle(type, publicIdentifier, lang); + return zip(this.customLoader.getTranslation(lang), overrideBundle).pipe(mergeMap(([root, override]) => { + this.translateService.setTranslation(lang, root, false); + this.translateService.setTranslation(lang, override, true); + this.translateService.use(lang); + return of(true); + })); + } + + useTranslationForRoot(lang: string): Observable { + return this.useTranslation(null, '', lang); + } + + private getOverrideBundle(type: PurchaseContextType, publicIdentifier: string, lang: string): Observable { + if (type === 'event' && publicIdentifier) { + return this.eventService.getEvent(publicIdentifier) + .pipe( + catchError(e => of({i18nOverride: {}})), + map(e => e.i18nOverride[lang] || {}) + ); + } + return of({}); + } +} + +const translationCache: {[key: string]: Observable} = {}; + +@Injectable({providedIn: 'root'}) +export class CustomLoader implements TranslateLoader { + + constructor(private http: HttpClient) { + } + + getTranslation(lang: string): Observable { + if (!translationCache[lang]) { + const preloadBundle = document.getElementById('preload-bundle'); + if (preloadBundle && preloadBundle.getAttribute('data-param') === lang) { + translationCache[lang] = of(JSON.parse(preloadBundle.textContent)).pipe(shareReplay(1)); + } else { + translationCache[lang] = this.http.get(`/api/v2/public/i18n/bundle/${lang}`).pipe(shareReplay(1)); + } + } + return translationCache[lang]; + } +} diff --git a/frontend/projects/public/src/app/shared/info.service.ts b/frontend/projects/public/src/app/shared/info.service.ts new file mode 100644 index 0000000000..526ca847a1 --- /dev/null +++ b/frontend/projects/public/src/app/shared/info.service.ts @@ -0,0 +1,28 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {Observable, of} from 'rxjs'; +import {Info} from '../model/info'; +import {shareReplay} from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class InfoService { + + private infoCache: Observable; + + constructor(private http: HttpClient) { } + + getInfo(): Observable { + if (!this.infoCache) { + const preloadInfo = document.getElementById('preload-info'); + if (preloadInfo) { + this.infoCache = of(JSON.parse(preloadInfo.textContent)).pipe(shareReplay(1)); + } else { + this.infoCache = this.http.get('/api/v2/info').pipe(shareReplay(1)); + } + setTimeout(() => { this.infoCache = null; }, 60000 * 10); // clean up cache after 10 minute + } + return this.infoCache; + } +} diff --git a/frontend/projects/public/src/app/shared/invalid-feedback.directive.ts b/frontend/projects/public/src/app/shared/invalid-feedback.directive.ts new file mode 100644 index 0000000000..b24fbbf183 --- /dev/null +++ b/frontend/projects/public/src/app/shared/invalid-feedback.directive.ts @@ -0,0 +1,122 @@ +import {Directive, ElementRef, Input, OnDestroy, OnInit, Optional} from '@angular/core'; +import {AbstractControl, FormControlName, UntypedFormGroup, ValidationErrors} from '@angular/forms'; +import {TranslateService} from '@ngx-translate/core'; +import {Subscription} from 'rxjs'; +import {ErrorDescriptor} from '../model/validated-response'; +import {removeDOMNode} from './event.service'; + +@Directive({ + selector: '[appInvalidFeedback]' +}) +export class InvalidFeedbackDirective implements OnInit, OnDestroy { + + private subs: Subscription[] = []; + + @Input() + invalidFeedbackInLabel: boolean; + + @Input() + invalidFeedbackFieldName: string; + + @Input() + invalidFeedbackForm: UntypedFormGroup; + + private targetControl: AbstractControl; + + constructor(private element: ElementRef, @Optional() private control: FormControlName, private translation: TranslateService) { + } + + ngOnInit(): void { + + if (this.control == null && this.invalidFeedbackForm != null && this.invalidFeedbackFieldName != null) { + this.targetControl = this.invalidFeedbackForm.get(this.invalidFeedbackFieldName); + this.targetControl.statusChanges.subscribe(e => { + this.checkValidation(); + }); + } + + if (this.control) { + this.control.statusChanges.subscribe(e => { + this.checkValidation(); + }); + } + } + + private clearSubs(): void { + this.subs.forEach(s => { + if (s) { + s.unsubscribe(); + } + }); + this.subs = []; + } + + ngOnDestroy(): void { + this.clearSubs(); + } + + private get errors(): ValidationErrors { + return this.targetControl ? this.targetControl.errors : this.control.errors; + } + + private checkValidation(): void { + + let errorContainerElement: HTMLElement; + + if (this.invalidFeedbackInLabel) { + errorContainerElement = this.element.nativeElement.parentElement.nextElementSibling; + } else { + errorContainerElement = this.element.nativeElement.nextElementSibling; + } + + this.clearSubs(); + if (this.errors && this.errors.serverError && this.errors.serverError.length > 0) { + this.element.nativeElement.classList.add('is-invalid'); + if (isInvalidFeedbackContainer(errorContainerElement)) { + // remove messages that are already presents + const rangeObj = new Range(); + rangeObj.selectNodeContents(errorContainerElement); + rangeObj.deleteContents(); + this.addErrorMessages(errorContainerElement); + // + } else { + const container = document.createElement('div'); + container.classList.add('invalid-feedback'); + this.addErrorMessages(container); + if (this.invalidFeedbackInLabel) { + container.classList.add('force-display'); + this.element.nativeElement.parentNode.insertAdjacentElement('afterEnd', container); + } else { + this.element.nativeElement.insertAdjacentElement('afterEnd', container); + } + } + } else { + this.element.nativeElement.classList.remove('is-invalid'); + if (isInvalidFeedbackContainer(errorContainerElement)) { + removeDOMNode(errorContainerElement); + } + } + } + + private addErrorMessages(container: HTMLElement): void { + this.errors.serverError.forEach((e: ErrorDescriptor) => { + const msg = document.createElement('div'); + this.subs.push(this.translation.stream(e.code, e.arguments).subscribe(text => { + msg.textContent = text; + })); + container.appendChild(msg); + }); + } + +} + +function isInvalidFeedbackContainer(container: HTMLElement): boolean { + return container && container.classList.contains('invalid-feedback'); +} + + + +//
    +//
    +//
    + diff --git a/frontend/projects/public/src/app/shared/language-selector/language-selector.component.html b/frontend/projects/public/src/app/shared/language-selector/language-selector.component.html new file mode 100644 index 0000000000..6ef09d8516 --- /dev/null +++ b/frontend/projects/public/src/app/shared/language-selector/language-selector.component.html @@ -0,0 +1,8 @@ +
    + +
    + +
    +
    diff --git a/frontend/projects/public/src/app/shared/language-selector/language-selector.component.ts b/frontend/projects/public/src/app/shared/language-selector/language-selector.component.ts new file mode 100644 index 0000000000..efdfc48e41 --- /dev/null +++ b/frontend/projects/public/src/app/shared/language-selector/language-selector.component.ts @@ -0,0 +1,66 @@ +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {Language} from '../../model/event'; +import {Router} from '@angular/router'; +import {I18nService} from '../i18n.service'; +import {Observable} from 'rxjs'; + +@Component({ + selector: 'app-language-selector', + templateUrl: './language-selector.component.html' +}) +export class LanguageSelectorComponent implements OnInit, OnChanges { + + @Input() + contentLanguages: Language[]; + private selectedLanguage: string; + private initialized = false; + currentLanguage: string; + filteredLanguages: Language[]; + + constructor(private i18nService: I18nService, private router: Router) { } + + ngOnInit(): void { + this.selectedLanguage = this.i18nService.getCurrentLang(); + this.buildValues(); + this.initialized = true; + } + + ngOnChanges(changes: SimpleChanges): void { + if (this.initialized && changes.contentLanguages) { + this.buildValues(); + } + } + + + + private buildValues(): void { + if (this.contentLanguages != null && this.contentLanguages.length > 0) { + let currentLang = this.contentLanguages.find(cl => cl.locale === this.selectedLanguage); + const languageNotFound = currentLang == null; + if (languageNotFound) { + currentLang = this.contentLanguages[0]; + this.changeLanguage(currentLang.locale); + } + this.currentLanguage = currentLang ? currentLang.displayLanguage : this.contentLanguages[0].displayLanguage; + this.filteredLanguages = this.contentLanguages.filter(cl => cl !== currentLang) + .sort((a, b) => a.displayLanguage.toLowerCase() > b.displayLanguage.toLowerCase() ? 1 : -1); + } + } + + public changeLanguage(lang: string): void { + if (this.selectedLanguage === lang) { + return; + } + const eventShortName = this.router.routerState.snapshot.root.firstChild ? this.router.routerState.snapshot.root.firstChild.params['eventShortName'] : null; + let observable: Observable; + if (eventShortName != null) { + observable = this.i18nService.useTranslation('event', eventShortName, lang); + } else { + observable = this.i18nService.useTranslationForRoot(lang); + } + observable.subscribe(() => { + this.selectedLanguage = this.i18nService.getCurrentLang(); + this.buildValues(); + }); + } +} diff --git a/frontend/projects/public/src/app/shared/purchase-context.service.ts b/frontend/projects/public/src/app/shared/purchase-context.service.ts new file mode 100644 index 0000000000..d8caa7dc7b --- /dev/null +++ b/frontend/projects/public/src/app/shared/purchase-context.service.ts @@ -0,0 +1,26 @@ +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import {EventService} from './event.service'; +import {SubscriptionService} from './subscription.service'; +import {PurchaseContext} from '../model/purchase-context'; + +@Injectable({ + providedIn: 'root' +}) +export class PurchaseContextService { + + constructor(private eventService: EventService, private subscriptionService: SubscriptionService) { } + + + getContext(type: PurchaseContextType, publicIdentifier: string): Observable { + if (type === 'event') { + return this.eventService.getEvent(publicIdentifier); + } else if (type === 'subscription') { + return this.subscriptionService.getSubscriptionById(publicIdentifier); + } else { + throw new Error(); + } + } +} + +export type PurchaseContextType = 'event' | 'subscription'; diff --git a/frontend/projects/public/src/app/shared/reservation.service.ts b/frontend/projects/public/src/app/shared/reservation.service.ts new file mode 100644 index 0000000000..49a3c0e80c --- /dev/null +++ b/frontend/projects/public/src/app/shared/reservation.service.ts @@ -0,0 +1,90 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {Observable} from 'rxjs'; +import {ReservationRequest} from '../model/reservation-request'; +import {ValidatedResponse} from '../model/validated-response'; +import {OverviewConfirmation} from '../model/overview-confirmation'; +import {ReservationInfo, ReservationStatusInfo} from '../model/reservation-info'; +import {ReservationPaymentResult} from '../model/reservation-payment-result'; +import {TransactionInitializationToken} from '../model/payment'; +import {DynamicDiscount} from '../model/event-code'; +import {PurchaseContextType} from './purchase-context.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ReservationService { + + constructor(private http: HttpClient) { } + + reserveTickets(eventShortName: string, reservation: ReservationRequest, lang: string): Observable> { + return this.http.post>(`/api/v2/public/event/${eventShortName}/reserve-tickets`, reservation, {params: {lang: lang}}); + } + + getReservationInfo(reservationId: string): Observable { + return this.http.get(`/api/v2/public/reservation/${reservationId}`); + } + + getReservationStatusInfo(reservationId: string): Observable { + return this.http.get(`/api/v2/public/reservation/${reservationId}/status`); + } + + cancelPendingReservation(reservationId: string): Observable { + return this.http.delete(`/api/v2/public/reservation/${reservationId}`); + } + + validateToOverview(reservationId: string, contactsAndTicket: any, lang: string, ignoreWarnings: boolean): Observable> { + const url = `/api/v2/public/reservation/${reservationId}/validate-to-overview`; + return this.http.post>(url, contactsAndTicket, {params: {lang: lang, ignoreWarnings: '' + ignoreWarnings}}); + } + + confirmOverview(reservationId: string, overviewForm: OverviewConfirmation, lang: string): Observable> { + const url = `/api/v2/public/reservation/${reservationId}`; + return this.http.post>(url, overviewForm, {params: {lang: lang}}); + } + + backToBooking(reservationId: string): Observable { + return this.http.post(`/api/v2/public/reservation/${reservationId}/back-to-booking`, {}); + } + + reSendReservationEmail(purchaseContextType: PurchaseContextType, publicIdentifier: string, reservationId: string, lang: string): Observable { + return this.http.post(`/api/v2/public/${purchaseContextType}/${publicIdentifier}/reservation/${reservationId}/re-send-email`, {}, {params: {lang: lang}}); + } + + initPayment(reservationId: string): Observable { + return this.http.post(`/api/v2/public/reservation/${reservationId}/payment/CREDIT_CARD/init`, {}); + } + + getPaymentStatus(reservationId: string): Observable { + return this.http.get(`/api/v2/public/reservation/${reservationId}/payment/CREDIT_CARD/status`); + } + + forcePaymentStatusCheck(reservationId: string): Observable { + return this.http.get(`/api/v2/public/reservation/${reservationId}/transaction/force-check`); + } + + removePaymentToken(reservationId: string): Observable { + return this.http.delete(`/api/v2/public/reservation/${reservationId}/payment/token`); + } + + resetPaymentStatus(reservationId: string): Observable { + return this.http.delete(`/api/v2/public/reservation/${reservationId}/payment`); + } + + registerPaymentAttempt(reservationId: string): Observable { + return this.http.put(`/api/v2/public/reservation/${reservationId}/payment`, {}); + } + + checkDynamicDiscountAvailability(eventShortName: string, reservation: ReservationRequest): Observable { + return this.http.post(`/api/v2/public/event/${eventShortName}/check-discount`, reservation); + } + + applySubscriptionCode(reservationId: string, code: string, email: string): Observable> { + return this.http.post>(`/api/v2/public/reservation/${reservationId}/apply-code/`, {code: code, email: email, amount: 1, type: 'SUBSCRIPTION'}); + } + + removeSubscription(reservationId: string): Observable { + return this.http.delete(`/api/v2/public/reservation/${reservationId}/remove-code`, {params: {type: 'SUBSCRIPTION'}}); + } + +} diff --git a/frontend/projects/public/src/app/shared/shared.module.ts b/frontend/projects/public/src/app/shared/shared.module.ts new file mode 100644 index 0000000000..f1e049590f --- /dev/null +++ b/frontend/projects/public/src/app/shared/shared.module.ts @@ -0,0 +1,43 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {TranslateModule} from '@ngx-translate/core'; +import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; +import {NgbDropdownModule, NgbToastModule} from '@ng-bootstrap/ng-bootstrap'; + +import {LanguageSelectorComponent} from './language-selector/language-selector.component'; +import {PurchaseContextHeaderComponent} from './event-header/purchase-context-header.component'; +import {InvalidFeedbackDirective} from './invalid-feedback.directive'; +import {ClipboardCopyDirective} from './clipboard-copy/clipboard-copy.directive'; +import {FeedbackComponent} from './feedback/feedback.component'; +import {WarningModalComponent} from './warning-modal/warning-modal.component'; +import {TopBarComponent} from './topbar/top-bar.component'; + +@NgModule({ + declarations: [ + LanguageSelectorComponent, + PurchaseContextHeaderComponent, + InvalidFeedbackDirective, + ClipboardCopyDirective, + FeedbackComponent, + WarningModalComponent, + TopBarComponent + ], + imports: [ + CommonModule, + TranslateModule.forChild(), + FontAwesomeModule, + NgbDropdownModule, + NgbToastModule + ], + exports: [ + LanguageSelectorComponent, + PurchaseContextHeaderComponent, + InvalidFeedbackDirective, + ClipboardCopyDirective, + FeedbackComponent, + WarningModalComponent, + TopBarComponent + ], +}) +export class SharedModule { } diff --git a/frontend/projects/public/src/app/shared/subscription.service.ts b/frontend/projects/public/src/app/shared/subscription.service.ts new file mode 100644 index 0000000000..b9fac264f0 --- /dev/null +++ b/frontend/projects/public/src/app/shared/subscription.service.ts @@ -0,0 +1,48 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {Observable} from 'rxjs'; +import {BasicSubscriptionInfo, SubscriptionInfo} from '../model/subscription'; +import {ValidatedResponse} from '../model/validated-response'; +import {shareReplay} from 'rxjs/operators'; +import {SearchParams} from '../model/search-params'; + +@Injectable({ + providedIn: 'root' +}) +export class SubscriptionService { + + + private subscriptionCache: {[key: string]: Observable} = {}; + + constructor(private http: HttpClient) { } + + getSubscriptions(searchParams?: SearchParams): Observable { + const params = searchParams?.toHttpParams(); + return this.http.get('/api/v2/public/subscriptions', { + responseType: 'json', + params + }); + } + + getSubscriptionById(id: string): Observable { + if (!this.subscriptionCache[id]) { + this.subscriptionCache[id] = this.http.get(`/api/v2/public/subscription/${id}`).pipe(shareReplay(1)); + setTimeout(() => { + delete this.subscriptionCache[id]; + }, 60000 * 20); // clean up cache after 20 minutes + } + return this.subscriptionCache[id]; + } + + reserve(id: string): Observable> { + return this.http.post>(`/api/v2/public/subscription/${id}`, {}); + } +} + +export function getLocalizedContent(container: {[k: string]: string}, currentLang: string) { + const localizedContent = container[currentLang]; + if (localizedContent != null) { + return localizedContent; + } + return container[Object.keys(container)[0]]; +} diff --git a/frontend/projects/public/src/app/shared/ticket.service.ts b/frontend/projects/public/src/app/shared/ticket.service.ts new file mode 100644 index 0000000000..09ec6bebdf --- /dev/null +++ b/frontend/projects/public/src/app/shared/ticket.service.ts @@ -0,0 +1,135 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {from, Observable, of} from 'rxjs'; +import {TicketInfo} from '../model/ticket-info'; +import {UntypedFormBuilder, UntypedFormGroup} from '@angular/forms'; +import {AdditionalField, Ticket} from '../model/ticket'; +import {ValidatedResponse} from '../model/validated-response'; +import {TicketsByTicketCategory} from '../model/reservation-info'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {ReleaseTicketComponent} from '../reservation/release-ticket/release-ticket.component'; +import {map, mergeMap} from 'rxjs/operators'; +import {User, UserAdditionalData} from '../model/user'; +import {DateValidity} from '../model/date-validity'; +import {DownloadTicketComponent} from '../reservation/download-ticket/download-ticket.component'; +import {WalletConfiguration} from '../model/info'; + +@Injectable({ + providedIn: 'root' +}) +export class TicketService { + + private static getUserDataLabelValue(name: string, index: number, userLanguage?: string, additionalData?: UserAdditionalData): {l: string, v: string} | null { + if (additionalData != null && additionalData[name] && additionalData[name].values.length > index) { + const val = additionalData[name]; + return { l: val.label[userLanguage] || val.label[0], v: val.values[index] }; + } + return { l: null, v: null }; + } + + constructor( + private http: HttpClient, + private formBuilder: UntypedFormBuilder, + private modalService: NgbModal) { } + + getTicketInfo(eventName: string, ticketIdentifier: string): Observable { + return this.http.get(`/api/v2/public/event/${eventName}/ticket/${ticketIdentifier}`); + } + + getTicket(eventName: string, ticketIdentifier: string): Observable { + return this.http.get(`/api/v2/public/event/${eventName}/ticket/${ticketIdentifier}/full`); + } + + getOnlineCheckInInfo(eventName: string, ticketIdentifier: string, checkInCode: string): Observable { + return this.http.get(`/api/v2/public/event/${eventName}/ticket/${ticketIdentifier}/code/${checkInCode}/check-in-info`, { + params: { + tz: this.retrieveTimezone() + } + }); + } + + sendTicketByEmail(eventName: string, ticketIdentifier: string): Observable { + return this.http.post(`/api/v2/public/event/${eventName}/ticket/${ticketIdentifier}/send-ticket-by-email`, {}); + } + + buildFormGroupForTicket(ticket: Ticket, user?: User): UntypedFormGroup { + return this.formBuilder.group(this.buildTicket(ticket, user)); + } + + + updateTicket(eventName: string, ticketIdentifier: string, ticket: any): Observable> { + return this.http.put>(`/api/v2/public/event/${eventName}/ticket/${ticketIdentifier}`, ticket); + } + + openReleaseTicket(ticket: Ticket, eventName: string): Observable { + return from(this.modalService.open(ReleaseTicketComponent, {centered: true}).result) + .pipe(mergeMap(res => { + if (res === 'yes') { + return this.releaseTicket(eventName, ticket.uuid); + } else { + return of(false); + } + })); + } + + openDownloadTicket(ticket: Ticket, eventName: string, walletConfiguration: WalletConfiguration): Observable { + const modal = this.modalService.open(DownloadTicketComponent, {centered: true}); + const instance: DownloadTicketComponent = modal.componentInstance; + instance.ticket = ticket; + instance.eventName = eventName; + instance.walletConfiguration = walletConfiguration; + return from(modal.result) + .pipe(map(_ => true)); + } + + releaseTicket(eventName: string, ticketIdentifier: string): Observable { + return this.http.delete(`/api/v2/public/event/${eventName}/ticket/${ticketIdentifier}`, {}); + } + + private buildTicket(ticket: Ticket, user?: User): {firstName: string, lastName: string, email: string, userLanguage, additional: UntypedFormGroup} { + return { + firstName: ticket.firstName || user?.firstName, + lastName: ticket.lastName || user?.lastName, + email: ticket.email || user?.emailAddress, + userLanguage: ticket.userLanguage, + additional: this.buildAdditionalFields(ticket.ticketFieldConfigurationBeforeStandard, + ticket.ticketFieldConfigurationAfterStandard, ticket.userLanguage, user?.profile?.additionalData) + }; + } + + private buildAdditionalFields(before: AdditionalField[], after: AdditionalField[], userLanguage: string, userData?: UserAdditionalData): UntypedFormGroup { + const additional = {}; + if (before) { + this.buildSingleAdditionalField(before, additional, userLanguage, userData); + } + if (after) { + this.buildSingleAdditionalField(after, additional, userLanguage, userData); + } + return this.formBuilder.group(additional); + } + + private buildSingleAdditionalField(a: AdditionalField[], additional: {}, userLanguage: string, userData?: UserAdditionalData): void { + a.forEach(f => { + const arr = []; + + if (f.type === 'checkbox') { // pre-fill with empty values for the checkbox cases, as we can have multiple values! + for (let i = 0; i < f.restrictedValues.length; i++) { + arr.push(this.formBuilder.control(null)); + } + } + + f.fields.forEach(field => { + arr[field.fieldIndex] = this.formBuilder.control(field.fieldValue || TicketService.getUserDataLabelValue(f.name, field.fieldIndex, userLanguage, userData).v); + }); + additional[f.name] = this.formBuilder.array(arr); + }); + } + + private retrieveTimezone(): string | null { + try { + return Intl.DateTimeFormat().resolvedOptions().timeZone; + } catch (e) { + return null; + } + } +} diff --git a/frontend/projects/public/src/app/shared/topbar/top-bar.component.html b/frontend/projects/public/src/app/shared/topbar/top-bar.component.html new file mode 100644 index 0000000000..c5641af6d7 --- /dev/null +++ b/frontend/projects/public/src/app/shared/topbar/top-bar.component.html @@ -0,0 +1,25 @@ +
    +
    + +
    +
    +
    + {{user?.firstName}} {{user?.lastName}} +
    +
    + +
    + + + +
    +
    + +
    +
    diff --git a/frontend/projects/public/src/app/shared/topbar/top-bar.component.ts b/frontend/projects/public/src/app/shared/topbar/top-bar.component.ts new file mode 100644 index 0000000000..1e1a9622ad --- /dev/null +++ b/frontend/projects/public/src/app/shared/topbar/top-bar.component.ts @@ -0,0 +1,73 @@ +import {AfterViewInit, Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {UserService} from '../user.service'; +import {ANONYMOUS, User} from '../../model/user'; +import {Language} from '../../model/event'; +import {Subscription} from 'rxjs'; +import {Router} from '@angular/router'; +import {FeedbackService} from '../feedback/feedback.service'; +import {DELETE_ACCOUNT_CONFIRMATION, getFromSessionStorage, removeFromSessionStorage} from '../util'; + +@Component({ + selector: 'app-topbar', + templateUrl: './top-bar.component.html' +}) +export class TopBarComponent implements OnInit, OnDestroy, AfterViewInit { + + private authenticationStatusSubscription?: Subscription; + @Input() + contentLanguages: Language[]; + @Input() + displayLoginButton = true; + user?: User; + authenticationEnabled = false; + private root = document.querySelector(':root') as HTMLElement; + + constructor(private userService: UserService, + private router: Router, + private feedbackService: FeedbackService) { + } + + ngOnInit(): void { + this.authenticationStatusSubscription = this.userService.authenticationStatus.subscribe(authenticationStatus => { + this.authenticationEnabled = authenticationStatus.enabled; + if (authenticationStatus.user !== ANONYMOUS) { + this.user = authenticationStatus.user; + } + }); + } + + ngAfterViewInit(): void { + if (getFromSessionStorage(DELETE_ACCOUNT_CONFIRMATION) === 'y') { + this.feedbackService.showSuccess('my-profile.delete.success'); + removeFromSessionStorage(DELETE_ACCOUNT_CONFIRMATION); + } else if (this.root != null && this.root.getAttribute('data-signed-up') != null) { + this.feedbackService.showSuccess('my-profile.sign-up.success'); + this.root.removeAttribute('data-signed-up'); + } + } + + ngOnDestroy(): void { + this.authenticationStatusSubscription?.unsubscribe(); + } + + get anonymous(): boolean { + return this.user === ANONYMOUS; + } + + logout(): void { + this.userService.logout().subscribe(response => { + this.user = undefined; + if (!response.empty) { + window.location.href = response.targetUrl; + } + }); + } + + myOrders(): void { + this.router.navigate(['my-orders']); + } + + myProfile(): void { + this.router.navigate(['my-profile']); + } +} diff --git a/frontend/projects/public/src/app/shared/translate-description.pipe.ts b/frontend/projects/public/src/app/shared/translate-description.pipe.ts new file mode 100644 index 0000000000..d3be95cf6e --- /dev/null +++ b/frontend/projects/public/src/app/shared/translate-description.pipe.ts @@ -0,0 +1,19 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {TranslateService} from '@ngx-translate/core'; +import {getLocalizedContent} from './subscription.service'; + +@Pipe({ + name: 'translateDescription' +}) +export class TranslateDescriptionPipe implements PipeTransform { + + constructor(private translate: TranslateService) {} + + transform(value?: {[k: string]: string}): any { + if (value != null) { + const lang = this.translate.currentLang; + return getLocalizedContent(value, lang); + } + return null; + } +} diff --git a/frontend/projects/public/src/app/shared/user.service.ts b/frontend/projects/public/src/app/shared/user.service.ts new file mode 100644 index 0000000000..6483be9f58 --- /dev/null +++ b/frontend/projects/public/src/app/shared/user.service.ts @@ -0,0 +1,91 @@ +import {Injectable, OnDestroy} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {ANONYMOUS, AuthenticationStatus, ClientRedirect, PurchaseContextWithReservation, User} from '../model/user'; +import {BehaviorSubject, interval, Observable, of, Subscription} from 'rxjs'; +import {map, mergeMap, tap} from 'rxjs/operators'; +import {ValidatedResponse} from '../model/validated-response'; + +@Injectable({ providedIn: 'root' }) +export class UserService implements OnDestroy { + + private authStatusSubject = new BehaviorSubject({ enabled: false }); + private authStatusSubscription?: Subscription; + private authEnabled = false; + + constructor(private http: HttpClient) { + } + + initAuthenticationStatus(): Promise { + return new Promise((resolve) => this.loadUserStatus() + .subscribe(result => { + this.authStatusSubject.next(result); + resolve(true); + }, () => { + this.authStatusSubject.next({ enabled: false }); + resolve(true); // we resolve the promise anyway + })); + } + + private loadUserStatus(): Observable<{enabled: boolean, user?: User}> { + return this.http.get('/api/v2/public/user/authentication-enabled') + .pipe(mergeMap(enabled => { + if (enabled) { + return this.getUserIdentity().pipe(map(user => ({enabled, user}))); + } + return of({enabled, user: undefined}); + }), + tap(status => this.authEnabled = status.enabled) + ); + } + + public getUserIdentity(): Observable { + return this.http.get('/api/v2/public/user/me', { observe: 'response' }) + .pipe(map(response => { + if (response.status === 204) { + return ANONYMOUS; + } else { + return response.body; + } + })); + } + + ngOnDestroy(): void { + this.authStatusSubscription?.unsubscribe(); + } + + logout(): Observable { + return this.http.post('/api/v2/public/user/logout', {}) + .pipe(tap(() => { + this.authStatusSubject.next({ enabled: true }); + })); + } + + getOrders(): Observable> { + return this.http.get>('/api/v2/public/user/reservations'); + } + + updateUser(user: any): Observable> { + return this.http.post>('/api/v2/public/user/me', user); + } + + private startPolling(): void { + this.authStatusSubscription = interval(30_000).pipe( + mergeMap(() => this.loadUserStatus()) + ).subscribe(() => {}); + } + + get authenticationStatus(): Observable { + if (this.authStatusSubscription == null) { + this.startPolling(); + } + return this.authStatusSubject.asObservable(); + } + + deleteProfile(): Observable { + return this.http.delete('/api/v2/public/user/me').pipe( + tap(() => { + this.authStatusSubject.next({ enabled: true }); + }) + ); + } +} diff --git a/frontend/projects/public/src/app/shared/util.ts b/frontend/projects/public/src/app/shared/util.ts new file mode 100644 index 0000000000..311d09b2df --- /dev/null +++ b/frontend/projects/public/src/app/shared/util.ts @@ -0,0 +1,69 @@ +import {ReservationStatusChanged} from '../model/embedding-configuration'; +import {PurchaseContext} from '../model/purchase-context'; +import {ReservationInfo, ReservationStatus} from '../model/reservation-info'; +import {HttpErrorResponse} from '@angular/common/http'; +import {ReservationService} from './reservation.service'; +import {interval} from 'rxjs'; +import {filter, mergeMap} from 'rxjs/operators'; + +export const DELETE_ACCOUNT_CONFIRMATION = 'alfio.delete-account.confirmation'; + +export function writeToSessionStorage(key: string, value: string): void { + try { + window.sessionStorage.setItem(key, value); + } catch (e) { + // session storage might be disabled in some contexts + } +} + +export function getFromSessionStorage(key: string): string | null { + try { + return window.sessionStorage.getItem(key); + } catch (e) { + // session storage might be disabled in some contexts + return null; + } +} + +export function removeFromSessionStorage(key: string): void { + try { + window.sessionStorage.removeItem(key); + } catch (e) { + } +} + +export const mobile = window.matchMedia('(max-width: 767px)').matches; +export const embedded = window.parent !== window; + +export function notifyPaymentErrorToParent(purchaseContext: PurchaseContext, + reservationInfo: ReservationInfo, + reservationId: string, + err: Error) { + if (embedded && purchaseContext.embeddingConfiguration.enabled) { + window.parent.postMessage( + new ReservationStatusChanged(reservationInfo.status, reservationId, errorMessage(err)), + purchaseContext.embeddingConfiguration.notificationOrigin + ); + } +} + +export function pollReservationStatus(reservationId: string, + reservationService: ReservationService, + processSuccessful: (res: ReservationInfo) => void, + desiredStatuses: Array = ['COMPLETE']): void { + const subscription = interval(5000) + .pipe( + mergeMap(() => reservationService.getReservationInfo(reservationId)), + filter(reservationInfo => desiredStatuses.includes(reservationInfo.status)) + ).subscribe(reservationInfo => { + processSuccessful(reservationInfo); + subscription.unsubscribe(); + }); +} + +function errorMessage(err: Error): string { + if (err instanceof HttpErrorResponse) { + return `${err.message} (${err.status})`; + } + return err.message; +} diff --git a/frontend/projects/public/src/app/shared/validation-helper.ts b/frontend/projects/public/src/app/shared/validation-helper.ts new file mode 100644 index 0000000000..9200d6dd1e --- /dev/null +++ b/frontend/projects/public/src/app/shared/validation-helper.ts @@ -0,0 +1,78 @@ +import {AbstractControl} from '@angular/forms'; +import {ErrorDescriptor, ValidatedResponse} from '../model/validated-response'; +import {HttpErrorResponse} from '@angular/common/http'; + +function applyValidationErrors(form: AbstractControl, response: ValidatedResponse): ErrorDescriptor[] { + + if (response.errorCount === 0) { + return []; + } + + const globalErrors: ErrorDescriptor[] = []; + + response.validationErrors.forEach(err => { + + // form.get('tickets[207f224c-1df6-4994-9cb2-fa12eb36882d].email') -> not ok + // form.get('tickets.207f224c-1df6-4994-9cb2-fa12eb36882d.email') -> ok + const transformedFieldName = err.fieldName.replace(/\[/g, '.').replace(/\]/g, ''); + + const formControl = form.get(transformedFieldName); + + if (formControl) { + const formControlErr = formControl.getError('serverError'); + if (formControlErr) { + const errors = (formControlErr as ErrorDescriptor[]); + if (!containsWithKey(errors, err.code)) { + errors.push(err); + } + } else { + formControl.setErrors({serverError: [err]}); + } + formControl.markAsTouched(); + } else { + globalErrors.push(err); + } + }); + + // TODO: find better way -> this focus and scroll on the first invalid form input + setTimeout(() => { + // meh, should find a better way + const found = document.querySelectorAll('[appinvalidfeedback].ng-invalid, [appinvalidfeedback].is-invalid'); + if (found && found.length > 0) { + const elem = found[0] as HTMLElement; + window.scroll({ + behavior: 'smooth', + left: 0, + top: window.scrollY + elem.getBoundingClientRect().top - 100 + }); + elem.focus({ preventScroll: true }); + } + }, 10); + return globalErrors; +} + +function containsWithKey(errors: ErrorDescriptor[], key: string) { + for (let i = 0; i < errors.length; i++) { + if (errors[i].code === key) { + return true; + } + } + return false; +} + +export function handleServerSideValidationError(err: any, form: AbstractControl): ErrorDescriptor[] { + const errorObject = getErrorObject(err); + if (errorObject != null) { + return applyValidationErrors(form, errorObject); + } + return []; +} + +export function getErrorObject(err: any): ValidatedResponse | null { + if (err instanceof ValidatedResponse) { + return err; + } else if (err instanceof HttpErrorResponse && err.status === 422) { + return err.error; + } + return null; +} diff --git a/frontend/projects/public/src/app/shared/warning-modal/warning-modal.component.html b/frontend/projects/public/src/app/shared/warning-modal/warning-modal.component.html new file mode 100644 index 0000000000..f97da33fee --- /dev/null +++ b/frontend/projects/public/src/app/shared/warning-modal/warning-modal.component.html @@ -0,0 +1,17 @@ + diff --git a/frontend/projects/public/src/app/shared/warning-modal/warning-modal.component.ts b/frontend/projects/public/src/app/shared/warning-modal/warning-modal.component.ts new file mode 100644 index 0000000000..6fd1eb307f --- /dev/null +++ b/frontend/projects/public/src/app/shared/warning-modal/warning-modal.component.ts @@ -0,0 +1,17 @@ +import {Component, Input} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-warning-modal', + templateUrl: './warning-modal.component.html' +}) +export class WarningModalComponent { + + @Input() + message: string; + + @Input() + parameters: {[key: string]: string}; + + constructor(public activeModal: NgbActiveModal) {} +} diff --git a/frontend/projects/public/src/app/stepper/stepper.component.html b/frontend/projects/public/src/app/stepper/stepper.component.html new file mode 100644 index 0000000000..5142c194ed --- /dev/null +++ b/frontend/projects/public/src/app/stepper/stepper.component.html @@ -0,0 +1,32 @@ +
    +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    +
    + + +
    +
    +
    \ No newline at end of file diff --git a/frontend/projects/public/src/app/stepper/stepper.component.scss b/frontend/projects/public/src/app/stepper/stepper.component.scss new file mode 100644 index 0000000000..0749e1c366 --- /dev/null +++ b/frontend/projects/public/src/app/stepper/stepper.component.scss @@ -0,0 +1,60 @@ +/* based on https://material-ui.com/demos/steppers/ */ +.wizard2 { + display: flex; + flex-direction: row; + align-items: flex-start; + margin: 4rem 0; +} + +.wizard2 > div { + flex: 1; + position:relative +} + +.wizard2 > div > div:first-child { + flex-direction: column; + display: flex; + align-items: center; +} + +.wizard2 .badge { + display: inline-block; + min-width: 35px; + padding: 3px 7px; + font-size: 14px; + font-weight: 700; + line-height: 2; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: top; + background-color: #777; + border-radius: 17px; + min-height: 30px; +} + +.wizard2 .wizard2-line { + top: 17px; + left: calc(50% + 20px); + right: calc(-50% + 20px); + position: absolute; + border-top: 1px solid #bdbdbd; +} + +.badge-success { + background-color: #449d44 !important; +} + +.wizard2 .wizard2-current .badge { + background-color: #007ACC; +} + +.wizard2 span:nth-child(2) { + margin-top: 1em; + text-align: center; +} + +.wizard2 .wizard2-current span:nth-child(2) { + font-weight:bold; + color: black; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/stepper/stepper.component.ts b/frontend/projects/public/src/app/stepper/stepper.component.ts new file mode 100644 index 0000000000..841be0c734 --- /dev/null +++ b/frontend/projects/public/src/app/stepper/stepper.component.ts @@ -0,0 +1,20 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'app-stepper', + templateUrl: './stepper.component.html', + styleUrls: ['./stepper.component.scss'] +}) +export class StepperComponent { + + @Input() + free = true; + + @Input() + currentStep = 1; + + @Input() + inProgress = false; + + constructor() { } +} diff --git a/frontend/projects/public/src/app/subscription-display/subscription-display.component.html b/frontend/projects/public/src/app/subscription-display/subscription-display.component.html new file mode 100644 index 0000000000..4508331ba1 --- /dev/null +++ b/frontend/projects/public/src/app/subscription-display/subscription-display.component.html @@ -0,0 +1,30 @@ + +
    +
    + +
    +
    +
    +

    {{ subscription.title[translateService.currentLang] }}

    +
    + +
    +
    +
    + +
    + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/frontend/projects/public/src/app/subscription-display/subscription-display.component.scss b/frontend/projects/public/src/app/subscription-display/subscription-display.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/public/src/app/subscription-display/subscription-display.component.ts b/frontend/projects/public/src/app/subscription-display/subscription-display.component.ts new file mode 100644 index 0000000000..fe978ad1cf --- /dev/null +++ b/frontend/projects/public/src/app/subscription-display/subscription-display.component.ts @@ -0,0 +1,62 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; +import {SubscriptionInfo} from '../model/subscription'; +import {AnalyticsService} from '../shared/analytics.service'; +import {InfoService} from '../shared/info.service'; +import {SubscriptionService} from '../shared/subscription.service'; +import {zip} from 'rxjs'; +import {TranslateService} from '@ngx-translate/core'; +import {I18nService} from '../shared/i18n.service'; +import {getErrorObject} from '../shared/validation-helper'; +import {ErrorDescriptor} from '../model/validated-response'; +import {FeedbackService} from '../shared/feedback/feedback.service'; + +@Component({ + selector: 'app-subscription-display', + templateUrl: './subscription-display.component.html', + styleUrls: ['./subscription-display.component.scss'] +}) +export class SubscriptionDisplayComponent implements OnInit { + + + submitError: ErrorDescriptor; + subscription: SubscriptionInfo; + subscriptionId: string; + + constructor(private route: ActivatedRoute, + private router: Router, + private subscriptionService: SubscriptionService, + private info: InfoService, + private analytics: AnalyticsService, + public translateService: TranslateService, + private i18nService: I18nService, + private feedbackService: FeedbackService) { } + + ngOnInit(): void { + this.route.params.subscribe(params => { + this.subscriptionId = params['id']; + zip(this.subscriptionService.getSubscriptionById(this.subscriptionId), this.info.getInfo()).subscribe(([subscription, info]) => { + this.subscription = subscription; + this.i18nService.setPageTitle('show-subscription.header.title', subscription); + this.analytics.pageView(info.analyticsConfiguration); + }); + }); + } + + + submitForm() { + this.subscriptionService.reserve(this.subscriptionId).subscribe(res => { + this.router.navigate(['subscription', this.subscriptionId, 'reservation', res.value, 'book']); + }, (err) => { + const errorObject = getErrorObject(err); + let errorCode: string; + if (errorObject != null) { + errorCode = errorObject.validationErrors[0].code; + } else { + errorCode = 'reservation-page-error-status.header.title'; + } + this.feedbackService.showError(errorCode); + }); + } + +} diff --git a/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.html b/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.html new file mode 100644 index 0000000000..f6ef8578e2 --- /dev/null +++ b/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.html @@ -0,0 +1,17 @@ +
    + + +

    + + +
    + +
    + +
    +

    +
    + +
    + +
    diff --git a/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.scss b/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.ts b/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.ts new file mode 100644 index 0000000000..a4de278127 --- /dev/null +++ b/frontend/projects/public/src/app/subscription-list-all/subscription-list-all.component.ts @@ -0,0 +1,57 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute, Params, Router} from '@angular/router'; +import {TranslateService} from '@ngx-translate/core'; +import {BasicSubscriptionInfo} from '../model/subscription'; +import {AnalyticsService} from '../shared/analytics.service'; +import {I18nService} from '../shared/i18n.service'; +import {InfoService} from '../shared/info.service'; +import {SubscriptionService} from '../shared/subscription.service'; +import {of, zip} from 'rxjs'; +import {Language, TermsPrivacyLinksContainer} from '../model/event'; +import {globalTermsPrivacyLinks} from '../model/info'; +import {filterAvailableLanguages} from '../model/purchase-context'; +import {mergeMap} from 'rxjs/operators'; +import {SearchParams} from '../model/search-params'; + +@Component({ + selector: 'app-subscription-list-all', + templateUrl: './subscription-list-all.component.html', + styleUrls: ['./subscription-list-all.component.scss'] +}) +export class SubscriptionListAllComponent implements OnInit { + + + subscriptions: BasicSubscriptionInfo[]; + languages: Language[]; + linksContainer: TermsPrivacyLinksContainer; + queryParams: Params; + + constructor(private subscriptionService: SubscriptionService, + private i18nService: I18nService, + private router: Router, + public translate: TranslateService, + private info: InfoService, + private analytics: AnalyticsService, + private route: ActivatedRoute) { } + + ngOnInit(): void { + zip(this.route.queryParams, this.route.params).pipe( + mergeMap(([params, pathParams]) => { + const searchParams = SearchParams.fromQueryAndPathParams(params, pathParams); + return zip(this.subscriptionService.getSubscriptions(searchParams), this.info.getInfo(), of(searchParams), this.i18nService.getAvailableLanguages()); + }) + ).subscribe(([res, info, searchParams, activeLanguages]) => { + this.queryParams = searchParams.toParams(); + if (res.length === 1) { + this.router.navigate(['/subscription', res[0].id], {replaceUrl: true, queryParams: this.queryParams}); + } else { + this.subscriptions = res; + this.analytics.pageView(info.analyticsConfiguration); + this.linksContainer = globalTermsPrivacyLinks(info); + this.languages = filterAvailableLanguages(activeLanguages, res); + this.i18nService.setPageTitle('subscription.header.title', null); + } + }); + } + +} diff --git a/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.html b/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.html new file mode 100644 index 0000000000..f57bbfea8d --- /dev/null +++ b/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.html @@ -0,0 +1,49 @@ +
    + +
    +
    {{'show-event.by'|translate}} {{subscription.organizationName}}
    +
    + + +
    +
    + {{ 'subscription.detail.validity.NOT_SET.description' | translate : { '0': subscription.maxEntries, '1': ('subscription.usage-type.'+subscription.usageType) | translate } }} +
    +
    + + +
    +
    + {{ 'subscription.detail.validity.STANDARD.description' | translate : { '0': subscription.validityUnits, '1': ('subscription.time-unit.'+subscription.validityTimeUnit | translate), '2': ('subscription.usage-type.'+subscription.usageType) | translate } }} +
    +
    + + +
    +
    +
    +
    +
    + + {{ validFrom }} +   ({{subscription.timeZone}}) +
    +
    + + {{ validTo }} +   ({{subscription.timeZone}}) +
    +
    {{ 'subscription.usage-type.' + subscription.usageType | translate }}
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    {{owner.firstName}} {{owner.lastName}} ({{owner.email}})
    +
    +
    diff --git a/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.scss b/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.scss new file mode 100644 index 0000000000..3ce7ee34f6 --- /dev/null +++ b/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.scss @@ -0,0 +1,7 @@ +.col-icon { + width: 40px; +} + +.col-text { + width: calc(100% - 40px); +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.ts b/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.ts new file mode 100644 index 0000000000..b16c7b5b26 --- /dev/null +++ b/frontend/projects/public/src/app/subscription-summary/subscription-summary.component.ts @@ -0,0 +1,67 @@ +import {Component, Input} from '@angular/core'; +import {SubscriptionSummaryData} from '../model/subscription'; +import {getLocalizedContent} from '../shared/subscription.service'; +import {isDifferentTimeZone} from '../shared/event.service'; +import {TranslateService} from '@ngx-translate/core'; +import {SubscriptionOwner} from '../model/reservation-info'; + +@Component({ + selector: 'app-subscription-summary', + templateUrl: './subscription-summary.component.html', + styleUrls: ['./subscription-summary.component.scss'] +}) +export class SubscriptionSummaryComponent { + + @Input() + subscription: SubscriptionSummaryData; + @Input() + owner?: SubscriptionOwner; + + constructor(private translateService: TranslateService) { + } + + get hasOnSaleTo(): boolean { + return this.subscription.formattedOnSaleTo != null; + } + + /* + get onSaleFrom(): string { + return getLocalizedContent(this.subscription.formattedOnSaleFrom, this.translateService.currentLang); + } + + get onSaleTo(): string { + return getLocalizedContent(this.subscription.formattedOnSaleTo, this.translateService.currentLang); + } + */ + + get displayTimeZoneInfo(): boolean { + const datesWithOffset = this.subscription.salePeriod; + return isDifferentTimeZone(datesWithOffset.startDateTime, datesWithOffset.startTimeZoneOffset) + || (datesWithOffset.endDateTime > 0 && isDifferentTimeZone(datesWithOffset.endDateTime, datesWithOffset.endTimeZoneOffset)); + } + + get validFrom(): string { + if (this.subscription.formattedValidFrom != null) { + return getLocalizedContent(this.subscription.formattedValidFrom, this.translateService.currentLang); + } + return ''; + } + + get hasValidTo(): boolean { + return this.subscription.formattedValidTo != null; + } + + get validTo(): string { + if (this.hasValidTo) { + return getLocalizedContent(this.subscription.formattedValidTo, this.translateService.currentLang); + } + return ''; + } + + hasData(owner: SubscriptionOwner): boolean { + return owner != null + && owner.firstName != null + && owner.lastName != null + && owner.email != null; + } +} diff --git a/frontend/projects/public/src/app/ticket-quantity-selector/ticket-quantity-selector.component.ts b/frontend/projects/public/src/app/ticket-quantity-selector/ticket-quantity-selector.component.ts new file mode 100644 index 0000000000..b7d1bd977e --- /dev/null +++ b/frontend/projects/public/src/app/ticket-quantity-selector/ticket-quantity-selector.component.ts @@ -0,0 +1,28 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {TicketCategory} from '../model/ticket-category'; +import {UntypedFormGroup} from '@angular/forms'; + +@Component({ + selector: 'app-ticket-quantity-selector', + templateUrl: './ticket-quantity-selector.html' +}) +export class TicketQuantitySelectorComponent { + + @Input() + parentGroup: UntypedFormGroup; + + @Input() + category: TicketCategory; + + @Input() + quantityRange: number[]; + + @Output() + valueChange = new EventEmitter(); + + formGroup: UntypedFormGroup; + + selectionChanged(): void { + this.valueChange.next(this.parentGroup.get('amount').value); + } +} diff --git a/frontend/projects/public/src/app/ticket-quantity-selector/ticket-quantity-selector.html b/frontend/projects/public/src/app/ticket-quantity-selector/ticket-quantity-selector.html new file mode 100644 index 0000000000..f1f5536ac7 --- /dev/null +++ b/frontend/projects/public/src/app/ticket-quantity-selector/ticket-quantity-selector.html @@ -0,0 +1,10 @@ +
    + + + + + + +
    diff --git a/frontend/projects/public/src/app/update-ticket/update-ticket.component.html b/frontend/projects/public/src/app/update-ticket/update-ticket.component.html new file mode 100644 index 0000000000..a5159c1d64 --- /dev/null +++ b/frontend/projects/public/src/app/update-ticket/update-ticket.component.html @@ -0,0 +1,73 @@ +
    +
    + +
    + +
    +
    +
    +
    + {{'event.online.not-started' | translate:{ '0' : ticketOnlineCheckInDate } }} + {{'event.online.started' | translate }} +
    +
    +

    {{'show-ticket.header.title' | translate:{ '0' : title } }}

    +
    +
    +
    +

    {{categoryName}}

    +

    {{ticket.fullName}}

    +

    {{'reservation-page-complete.ticket-not-assigned' | translate }}

    +
    + +
    + +
    + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    diff --git a/frontend/projects/public/src/app/update-ticket/update-ticket.component.ts b/frontend/projects/public/src/app/update-ticket/update-ticket.component.ts new file mode 100644 index 0000000000..ba236eb8d4 --- /dev/null +++ b/frontend/projects/public/src/app/update-ticket/update-ticket.component.ts @@ -0,0 +1,116 @@ +import {Component, OnInit} from '@angular/core'; +import {Event} from '../model/event'; +import {ActivatedRoute, Router} from '@angular/router'; +import {EventService} from '../shared/event.service'; +import {TicketService} from '../shared/ticket.service'; +import {zip} from 'rxjs'; +import {I18nService} from '../shared/i18n.service'; +import {AnalyticsService} from '../shared/analytics.service'; +import {HttpErrorResponse} from '@angular/common/http'; +import {UntypedFormGroup} from '@angular/forms'; +import {Ticket} from '../model/ticket'; +import {handleServerSideValidationError} from '../shared/validation-helper'; +import {TicketsByTicketCategory} from '../model/reservation-info'; +import {TranslateService} from '@ngx-translate/core'; +import {TicketAccessType} from '../model/ticket-category'; + +@Component({ + selector: 'app-update-ticket', + templateUrl: './update-ticket.component.html', + styleUrls: ['./update-ticket.scss'] +}) +export class UpdateTicketComponent implements OnInit { + + event: Event; + ticketIdentifier: string; + ticket: Ticket; + formGroup: UntypedFormGroup; + categoryName: string; + emailSent: boolean; + ticketFormVisible: boolean; + ticketAccessType: TicketAccessType; + + constructor( + private ticketService: TicketService, + private route: ActivatedRoute, + private router: Router, + private eventService: EventService, + private i18nService: I18nService, + private analytics: AnalyticsService, + private translate: TranslateService) { } + + public ngOnInit(): void { + this.route.params.subscribe(params => { + this.ticketIdentifier = params['ticketId']; + + const eventShortName = params['eventShortName']; + + zip(this.eventService.getEvent(eventShortName), this.ticketService.getTicket(eventShortName, this.ticketIdentifier)) + .subscribe(([event, ticketsByCategory]) => { + this.event = event; + this.i18nService.setPageTitle('show-ticket.header.title', event); + this.handleTicketResponse(ticketsByCategory); + this.analytics.pageView(event.analyticsConfiguration); + }, e => { + if (e instanceof HttpErrorResponse && e.status === 404) { + this.router.navigate(['']); + } + }); + }); + } + + private handleTicketResponse(ticketsByCategory: TicketsByTicketCategory): void { + this.ticketAccessType = ticketsByCategory.ticketAccessType; + this.ticket = ticketsByCategory.tickets[0]; + this.formGroup = this.ticketService.buildFormGroupForTicket(this.ticket); + this.categoryName = ticketsByCategory.name; + this.ticketFormVisible = !this.ticket.assigned; + } + + updateTicket(): void { + this.ticketService.updateTicket(this.event.shortName, this.ticket.uuid, this.formGroup.value).subscribe(res => { + if (res.success) { + this.ticketService.getTicket(this.event.shortName, this.ticketIdentifier) + .subscribe(t => this.handleTicketResponse(t)); + } + }, (err) => { + handleServerSideValidationError(err, this.formGroup); + }); + } + + sendEmailForTicket(): void { + this.ticketService.sendTicketByEmail(this.event.shortName, this.ticket.uuid).subscribe(res => { + if (res) { + this.emailSent = true; + } + }); + } + + releaseTicket() { + this.ticketService.openReleaseTicket(this.ticket, this.event.shortName) + .subscribe(released => { + if (released) { + this.router.navigate(['event', this.event.shortName], {replaceUrl: true}); + } + }); + } + + get isOnlineTicket(): boolean { + return this.event.format === 'ONLINE' + || (this.event.format === 'HYBRID' && this.ticketAccessType === 'ONLINE'); + } + + get ticketOnlineCheckInDate(): string { + return this.ticket.formattedOnlineCheckInDate[this.translate.currentLang]; + } + + get canUpdateTicket(): boolean { + return !this.ticket.locked + || this.ticket.ticketFieldConfigurationAfterStandard.length > 0 + || this.ticket.ticketFieldConfigurationBeforeStandard.length > 0; + } + + get title(): string { + return this.event.title[this.translate.currentLang]; + } +} diff --git a/frontend/projects/public/src/app/update-ticket/update-ticket.scss b/frontend/projects/public/src/app/update-ticket/update-ticket.scss new file mode 100644 index 0000000000..d7a58e8a44 --- /dev/null +++ b/frontend/projects/public/src/app/update-ticket/update-ticket.scss @@ -0,0 +1,23 @@ +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} + +.btn-default:hover { + color: #212529; + background-color: #e2e6ea; + border-color: #ccc; +} + +.btn-default:focus, .btn-default.focus { + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.sticky { + position: -webkit-sticky; + position: sticky; + bottom: 0px; + left: 0px; + z-index: 200; +} \ No newline at end of file diff --git a/frontend/projects/public/src/app/user-logged-in.guard.ts b/frontend/projects/public/src/app/user-logged-in.guard.ts new file mode 100644 index 0000000000..e13c65f30c --- /dev/null +++ b/frontend/projects/public/src/app/user-logged-in.guard.ts @@ -0,0 +1,27 @@ +import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router'; +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import {UserService} from './shared/user.service'; +import {first, map} from 'rxjs/operators'; +import {ANONYMOUS} from './model/user'; + +@Injectable({ + providedIn: 'root' +}) +export class UserLoggedInGuard implements CanActivate { + + constructor(private userService: UserService, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.userService.authenticationStatus + .pipe( + first(), + map(status => { + if (status.enabled && status.user !== ANONYMOUS) { + return true; + } + return this.router.parseUrl(''); + }) + ); + } +} diff --git a/frontend/projects/public/src/app/view-ticket/view-ticket.component.html b/frontend/projects/public/src/app/view-ticket/view-ticket.component.html new file mode 100644 index 0000000000..fb58186229 --- /dev/null +++ b/frontend/projects/public/src/app/view-ticket/view-ticket.component.html @@ -0,0 +1,73 @@ +
    +
    + +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +

    +
    +
    +
    {{ticketInfo.fullName}} <{{ticketInfo.email}}>
    +
    +
    {{ticketInfo.ticketCategoryName}}
    +
    +
    {{ticketInfo.uuid}}
    +
    +
    {{'ticket.order-information-values' | translate: { + '0': ticketInfo.reservationId, + '1': ticketInfo.reservationFullName + } }}
    +
    +
    + + +
    +

    +
    + +
    + + + +
    +
    +
    +
    + +
    +
    +
    +
    diff --git a/frontend/projects/public/src/app/view-ticket/view-ticket.component.scss b/frontend/projects/public/src/app/view-ticket/view-ticket.component.scss new file mode 100644 index 0000000000..69813edd3a --- /dev/null +++ b/frontend/projects/public/src/app/view-ticket/view-ticket.component.scss @@ -0,0 +1,12 @@ +@import "~bootstrap/scss/mixins"; +@import "~bootstrap/scss/functions"; +@import "~bootstrap/scss/variables"; + +img.wallet-link { + @include media-breakpoint-up(md) { + max-height: 56px; + } + @include media-breakpoint-down(md) { + max-width: 250px; + } +} diff --git a/frontend/projects/public/src/app/view-ticket/view-ticket.component.ts b/frontend/projects/public/src/app/view-ticket/view-ticket.component.ts new file mode 100644 index 0000000000..7d1cc25ca5 --- /dev/null +++ b/frontend/projects/public/src/app/view-ticket/view-ticket.component.ts @@ -0,0 +1,68 @@ +import {Component, OnInit} from '@angular/core'; +import {Event} from '../model/event'; +import {ActivatedRoute, Router} from '@angular/router'; +import {EventService} from '../shared/event.service'; +import {TicketService} from '../shared/ticket.service'; +import {TicketInfo} from '../model/ticket-info'; +import {zip} from 'rxjs'; +import {I18nService} from '../shared/i18n.service'; +import {AnalyticsService} from '../shared/analytics.service'; +import {HttpErrorResponse} from '@angular/common/http'; +import {InfoService} from '../shared/info.service'; +import {WalletConfiguration} from '../model/info'; + +@Component({ + selector: 'app-view-ticket', + templateUrl: './view-ticket.component.html', + styleUrls: ['./view-ticket.component.scss'] +}) +export class ViewTicketComponent implements OnInit { + + event: Event; + ticketIdentifier: string; + ticketInfo: TicketInfo; + private walletConfiguration: WalletConfiguration; + + constructor( + private ticketService: TicketService, + private route: ActivatedRoute, + private router: Router, + private eventService: EventService, + private i18nService: I18nService, + private analytics: AnalyticsService, + private infoService: InfoService) { } + + public ngOnInit(): void { + this.route.params.subscribe(params => { + this.ticketIdentifier = params['ticketId']; + + const eventShortName = params['eventShortName']; + + zip(this.eventService.getEvent(eventShortName), this.ticketService.getTicketInfo(eventShortName, this.ticketIdentifier), this.infoService.getInfo()) + .subscribe(([event, ticketInfo, generalInfo]) => { + this.event = event; + this.ticketInfo = ticketInfo; + this.i18nService.setPageTitle('show-ticket.header.title', event); + this.analytics.pageView(event.analyticsConfiguration); + this.walletConfiguration = generalInfo.walletConfiguration; + }, e => { + if (e instanceof HttpErrorResponse && e.status === 404) { + this.router.navigate(['']); + } + }); + }); + } + + get walletIntegrationEnabled(): boolean { + return this.walletConfiguration != null && + (this.walletConfiguration.gWalletEnabled || this.walletConfiguration.passEnabled); + } + + get gWalletEnabled(): boolean { + return this.walletConfiguration != null && this.walletConfiguration.gWalletEnabled; + } + + get passEnabled(): boolean { + return this.walletConfiguration != null && this.walletConfiguration.passEnabled; + } +} diff --git a/frontend/projects/public/src/app/waiting-room/waiting-room.component.html b/frontend/projects/public/src/app/waiting-room/waiting-room.component.html new file mode 100644 index 0000000000..003298114c --- /dev/null +++ b/frontend/projects/public/src/app/waiting-room/waiting-room.component.html @@ -0,0 +1,42 @@ +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    {{'common.hello' | translate }} {{ ticket.firstName }}

    +

    + {{'online.check-in.waiting-room.event-not-started' | translate }} + {{'online.check-in.waiting-room.event-started' | translate }} + {{ 'online.check-in.waiting-room.event-ended' | translate }} +

    +
    + + {{'online.check-in.waiting-room.event-not-started.start' | translate }} {{ checkInDate }} {{ 'common.time.at' | translate }} {{ checkInTime }} + + + {{ 'online.check-in.waiting-room.event-started.contact-organizers' | translate }} + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    diff --git a/frontend/projects/public/src/app/waiting-room/waiting-room.component.ts b/frontend/projects/public/src/app/waiting-room/waiting-room.component.ts new file mode 100644 index 0000000000..eeab798865 --- /dev/null +++ b/frontend/projects/public/src/app/waiting-room/waiting-room.component.ts @@ -0,0 +1,82 @@ +import {Component, OnInit} from '@angular/core'; +import {TicketService} from '../shared/ticket.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {EventService} from '../shared/event.service'; +import {I18nService} from '../shared/i18n.service'; +import {AnalyticsService} from '../shared/analytics.service'; +import {zip} from 'rxjs'; +import {HttpErrorResponse} from '@angular/common/http'; +import {mergeMap} from 'rxjs/operators'; +import {Event} from '../model/event'; +import {Ticket} from '../model/ticket'; +import {DateValidity} from '../model/date-validity'; +import {TranslateService} from '@ngx-translate/core'; + +@Component({ + selector: 'app-waiting-room', + templateUrl: './waiting-room.component.html' +}) +export class WaitingRoomComponent implements OnInit { + + event: Event; + ticketIdentifier: string; + ticket: Ticket; + checkInCode: string; + categoryName: string; + checkInInfo: DateValidity; + + constructor( + private ticketService: TicketService, + private route: ActivatedRoute, + private router: Router, + private eventService: EventService, + private i18nService: I18nService, + private analytics: AnalyticsService, + private translate: TranslateService) { } + + ngOnInit(): void { + this.route.params.pipe(mergeMap(params => { + this.ticketIdentifier = params['ticketId']; + const eventShortName = params['eventShortName']; + this.checkInCode = params['ticketCodeHash']; + return zip( + this.eventService.getEvent(eventShortName), + this.ticketService.getTicket(eventShortName, this.ticketIdentifier), + this.ticketService.getOnlineCheckInInfo(eventShortName, this.ticketIdentifier, this.checkInCode) + ); + })).subscribe(([event, ticketInfo, checkInInfo]) => { + this.event = event; + this.ticket = ticketInfo.tickets[0]; + this.categoryName = ticketInfo.name; + this.i18nService.setPageTitle('show-ticket.header.title', event); + this.analytics.pageView(event.analyticsConfiguration); + this.checkInInfo = checkInInfo; + }, e => { + if (e instanceof HttpErrorResponse && e.status === 404) { + this.router.navigate(['']); + } + }); + } + + get checkInDate(): string { + return this.checkInInfo.formattedBeginDate[this.translate.currentLang]; + } + + get checkInTime(): string { + return this.checkInInfo.formattedBeginTime[this.translate.currentLang]; + } + + get eventRunning(): boolean { + const now = new Date().getTime(); + const dates = this.checkInInfo.datesWithOffset; + return now > dates.startDateTime && now < dates.endDateTime; + } + + get eventStartsInTheFuture(): boolean { + return new Date().getTime() < this.checkInInfo.datesWithOffset.startDateTime; + } + + get eventEnded(): boolean { + return new Date().getTime() > this.checkInInfo.datesWithOffset.endDateTime; + } +} diff --git a/frontend/projects/public/src/app/xsrf.ts b/frontend/projects/public/src/app/xsrf.ts new file mode 100644 index 0000000000..957fb52fa5 --- /dev/null +++ b/frontend/projects/public/src/app/xsrf.ts @@ -0,0 +1,110 @@ +import {Inject, Injectable, Injector, INJECTOR, PLATFORM_ID} from '@angular/core'; +import { + HttpEvent, + HttpHandler, + HttpInterceptor, + HttpRequest, + HttpResponse, + HttpXsrfTokenExtractor +} from '@angular/common/http'; +import {DOCUMENT} from '@angular/common'; +import {Observable} from 'rxjs'; +import {tap} from 'rxjs/operators'; + +const GID_HEADER_NAME = 'x-auth-token'; +const XSRF_TOKEN_HEADER = 'xsrf-token'; + +@Injectable() +export class DOMXsrfTokenExtractor implements HttpXsrfTokenExtractor { + + lastToken: string | null = null; + + constructor(@Inject(DOCUMENT) private doc: Document, + @Inject(PLATFORM_ID) private platform: string) {} + + getToken(): string | null { + if (this.platform === 'server') { + return null; + } + return this.doc.head.querySelector('meta[name="XSRF_TOKEN"]')?.content || null; + } + + updateToken(newVal: string | null): void { + if (newVal == null || newVal === this.lastToken) { + return; + } + const element = retrieveHeadElement('XSRF_TOKEN', this.doc); + element.content = newVal; + this.lastToken = newVal; + } +} + +@Injectable() +export class DOMGidExtractor { + + lastToken: string | null = null; + + constructor(@Inject(DOCUMENT) private doc: Document, + @Inject(PLATFORM_ID) private platform: string) {} + + getToken(): string | null { + if (this.platform === 'server') { + return null; + } + return this.doc.head.querySelector('meta[name="GID"]')?.content || null; + } + + updateToken(newVal: string | null): void { + if (newVal == null || newVal === this.lastToken) { + return; + } + const element = retrieveHeadElement('GID', this.doc); + element.content = newVal; + this.lastToken = newVal; + } +} + +function retrieveHeadElement(name: string, doc: Document): HTMLMetaElement { + let element = doc.head.querySelector(`meta[name="${name}"]`); + if (element == null) { + // it should only happen in dev mode + element = doc.createElement('meta'); + element.name = name; + doc.head.append(element); + } + return element; +} + +@Injectable() +export class AuthTokenInterceptor implements HttpInterceptor { + + private domGidExtractor: DOMGidExtractor | null = null; + private domXsrfTokenExtractor: DOMXsrfTokenExtractor | null = null; + + constructor(@Inject(INJECTOR) private injector: Injector) { + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + this.init(); + return next.handle(req.clone({ + headers: req.headers.set(GID_HEADER_NAME, this.domGidExtractor?.getToken() || '') + })).pipe(tap(response => { + if (response instanceof HttpResponse) { + if (response.headers.has(GID_HEADER_NAME)) { + this.domGidExtractor?.updateToken(response.headers.get(GID_HEADER_NAME)); + } + if (req.method === 'GET' && response.headers.has(XSRF_TOKEN_HEADER)) { + this.domXsrfTokenExtractor?.updateToken(response.headers.get(XSRF_TOKEN_HEADER)); + } + } + })); + } + + private init(): void { + if (this.domGidExtractor == null) { + this.domGidExtractor = this.injector.get(DOMGidExtractor); + this.domXsrfTokenExtractor = this.injector.get(DOMXsrfTokenExtractor); + } + } + +} diff --git a/frontend/projects/public/src/assets/.gitkeep b/frontend/projects/public/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/projects/public/src/assets/img/payment/mollie-badge.png b/frontend/projects/public/src/assets/img/payment/mollie-badge.png new file mode 100644 index 0000000000..2a462b3d47 Binary files /dev/null and b/frontend/projects/public/src/assets/img/payment/mollie-badge.png differ diff --git a/frontend/projects/public/src/environments/environment.prod.ts b/frontend/projects/public/src/environments/environment.prod.ts new file mode 100644 index 0000000000..3612073bc3 --- /dev/null +++ b/frontend/projects/public/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/frontend/projects/public/src/environments/environment.ts b/frontend/projects/public/src/environments/environment.ts new file mode 100644 index 0000000000..7b4f817adb --- /dev/null +++ b/frontend/projects/public/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/frontend/projects/public/src/index.html b/frontend/projects/public/src/index.html new file mode 100644 index 0000000000..a23c559f3f --- /dev/null +++ b/frontend/projects/public/src/index.html @@ -0,0 +1,15 @@ + + + + + + + + Alf.io, the open source ticket reservation system + + +
    + +
    + + diff --git a/frontend/projects/public/src/karma.conf.js b/frontend/projects/public/src/karma.conf.js new file mode 100644 index 0000000000..ee9caa152d --- /dev/null +++ b/frontend/projects/public/src/karma.conf.js @@ -0,0 +1,31 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; \ No newline at end of file diff --git a/frontend/projects/public/src/main.ts b/frontend/projects/public/src/main.ts new file mode 100644 index 0000000000..484b5f3d3a --- /dev/null +++ b/frontend/projects/public/src/main.ts @@ -0,0 +1,12 @@ +import {enableProdMode} from '@angular/core'; +import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; + +import {AppModule} from './app/app.module'; +import {environment} from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/frontend/projects/public/src/polyfills.ts b/frontend/projects/public/src/polyfills.ts new file mode 100644 index 0000000000..d8a7f59d15 --- /dev/null +++ b/frontend/projects/public/src/polyfills.ts @@ -0,0 +1,60 @@ +/*************************************************************************************************** + * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. + */ +import '@angular/localize/init'; +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ +/*************************************************************************************************** + * BROWSER POLYFILLS + */ +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/frontend/projects/public/src/styles.scss b/frontend/projects/public/src/styles.scss new file mode 100644 index 0000000000..1193c9c376 --- /dev/null +++ b/frontend/projects/public/src/styles.scss @@ -0,0 +1,288 @@ +/* You can add global styles to this file, and also import other style files */ + +@import "font/font.scss"; + +$toast-max-width: 20vw; +$card-spacer-y: 1.25rem; +$card-spacer-x: 1.25rem; +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; +$custom-colors: ( + "default": $white +); + +// Merge the maps +$theme-colors: map-merge($theme-colors, $custom-colors); + +$custom-control-indicator-border-color: $gray-700; + +@import "bootstrap/scss/bootstrap"; + + +@import "@ng-select/ng-select/themes/default.theme.css"; + +.application-container { + background-color: white; +} + +.list-container { + +} + +@include media-breakpoint-up(md) { + body { + background-color: #f2f2f2; + } + .application-container { + margin-top: $border-radius; + margin-bottom: $border-radius; + border-radius: $border-radius; + } +} + + +.block-button { + width: 100%; + display: block +} + +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eee; +} + +body { + counter-reset: ticket-counter; +} + +.ticket-counter:before { + counter-increment: ticket-counter; + content: counter(ticket-counter); +} + +.rotate-45 { + transform: rotate(-45deg); +} + +@include media-breakpoint-up(sm) { + label.col-form-label, dt.align-right-mobile-aware { + text-align: right; + } +} + +.list-group-item { + border-left:none; + border-right:none; +} + +.list-group-item:first-child { + border-top:none; +} + +.list-group-item:last-child { + border-bottom:none; +} + +.img-responsive { + display: block; + max-width: 100%; + height: auto; +} + +.img-center { + margin:auto; +} + +.table>thead:first-child>tr:first-child>th { + border-top: 0; +} + +.table th { + font-size: $font-size-base; +} + +.text-align-right { + text-align: right; +} + +.no-margin-bottom { + margin-bottom: 0; +} + +.form-group label { + font-weight: bold; +} + +label.radio-inline { + font-weight: normal; +} + +.checkbox-in-form-group { + margin-top:38px; +} + +@include media-breakpoint-up(sm) { + .container { /*override bootstrap value*/ + max-width: 100%; + } +} + +@include media-breakpoint-up(xl) { + .container { + width: 960px; + } +} + +.invalid-feedback.force-display { + display: block; +} + +.c-container { + text-align: center; +} + +.c-container > div { + display: inline-block; +} + + +.btn-xs { + padding: .30rem .5rem; + font-size: .875rem; + line-height: .5; + border-radius: .2rem; +} + +.add-margin-bottom { + margin-bottom: 1rem; +} + +@media (max-width: 767px) { + .mobile-add-margin-bottom button.btn, + .mobile-add-margin-bottom a.btn + { + margin-bottom: 1rem; + } +} + + +/* basic style for markdown content */ + +.markdown-content img { + max-width:100%; +} + +.markdown-content table { + width:100%; +} + +.markdown-content table th, +.markdown-content table td { + padding-top:0.6rem; + padding-bottom:0.6rem; +} + +.markdown-content table th { + border-bottom: 2px solid #e3e3e3; +} + +.markdown-content table td { + border-top: 1px solid #e3e3e3; +} + +/* end markdown styling */ + +.ng-select.form-control { + padding: 0; +} + +.ng-select.ng-select-focused.form-control { + color: #495057; + background-color: #fff; + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.ng-select .ng-arrow-wrapper { + + font-weight: $form-select-font-weight; + line-height: $form-select-line-height; + color: $form-select-color; + background-color: $form-select-bg; + background-image: escape-svg($form-select-indicator); + background-repeat: no-repeat; + background-position: $form-select-bg-position; + background-size: $form-select-bg-size; + + .ng-arrow { + border: 0; + } +} + +.ng-select.form-control .ng-select-container { + border: none; + border-radius: 0; + color: #495057; + padding-left: 0!important; + outline: 0 !important; + background: transparent; +} + +.ng-select.form-control.ng-select-focused:not(.ng-select-opened)>.ng-select-container { + outline: 0!important; + box-shadow: none!important; +} + +div.preformatted { + word-wrap: break-word; + white-space: pre-wrap; +} + +h2 .badge { + font-size: 42%; + vertical-align: middle; +} + +h4 .badge { + font-size: 52%; + vertical-align: middle; +} + +div.is-invalid ~ div.invalid-feedback { + display: block; +} + +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} + +:not(.btn-check) + .btn + .btn-default:hover, .btn.btn-default:first-child:hover { + color: #212529; + background-color: #e2e6ea; + border-color: #ccc; +} + +.btn-default:focus, .btn-default.focus { + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.border-left-warning { + border-left: 5px solid var(--bs-warning); +} + +.border-left-success { + border-left: 5px solid var(--bs-success); +} + +.home-card { + &:hover { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; + } + h2.card-title { + font-size: 1.6rem; + } +} diff --git a/frontend/projects/public/src/test.ts b/frontend/projects/public/src/test.ts new file mode 100644 index 0000000000..ee6a36318c --- /dev/null +++ b/frontend/projects/public/src/test.ts @@ -0,0 +1,17 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import {getTestBed} from '@angular/core/testing'; +import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/frontend/projects/public/tsconfig.app.json b/frontend/projects/public/tsconfig.app.json new file mode 100644 index 0000000000..5714c6c309 --- /dev/null +++ b/frontend/projects/public/tsconfig.app.json @@ -0,0 +1,24 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/app", + "types": [], + /* temporarily disable strict checks, see https://www.typescriptlang.org/tsconfig */ + "strict": false, + "noPropertyAccessFromIndexSignature": false + }, + "angularCompilerOptions": { + /* temporarily disable strict checks */ + "strictPropertyInitialization": false, + "strictInjectionParameters": false, + "strictTemplates": false + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/frontend/projects/public/tsconfig.spec.json b/frontend/projects/public/tsconfig.spec.json new file mode 100644 index 0000000000..a9c0752ffe --- /dev/null +++ b/frontend/projects/public/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000000..a6650f1198 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,38 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "paths": { + "common": [ + "dist/common" + ] + }, + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "es2020", + "module": "es2020", + "useDefineForClassFields": false, + "lib": [ + "es2020", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/gradle.properties b/gradle.properties index 3e28826e05..a991bcc2b6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,8 @@ #Tue, 07 Apr 2015 22:45:24 +0200 group=alfio -version=2.0-M4 +version=2.0-M5-SNAPSHOT -sourceCompatibility=11 -targetCompatibility=11 +sourceCompatibility=17 +targetCompatibility=17 systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" - -# https://jitpack.io/#alfio-event/alf.io-public-frontend -> go to commit tab, set the version -alfioPublicFrontendVersion=908c55db5a \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2f..e708b1c023 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f371643eed..f42e62f372 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d95..4f906e0c81 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 9618d8d960..107acd32c4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/package-lock.json b/package-lock.json index 706b144637..faab095734 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,1361 @@ { "name": "mjml-to-html", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "mjml-to-html", + "version": "1.0.0", + "dependencies": { + "glob": "^7.1.6", + "mjml": "^4.10.1" + } + }, + "node_modules/@babel/runtime": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", + "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "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.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dependencies": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "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" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, + "node_modules/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "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.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "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/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "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==" + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "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==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "dependencies": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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==" + }, + "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==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-beautify": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", + "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "dependencies": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/juice": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/juice/-/juice-7.0.0.tgz", + "integrity": "sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q==", + "dependencies": { + "cheerio": "^1.0.0-rc.3", + "commander": "^5.1.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^5.0.0" + }, + "bin": { + "juice": "bin/juice" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/juice/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + }, + "node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mjml": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.10.1.tgz", + "integrity": "sha512-cD6F20yIMOUT9xaAVWLfk0DnhQSq6VkpD+LCf/RUWrxsxxkwPJtJfKfrP5TMeuWcmDFS9hfOBS3Jz+NmGh03jQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "mjml-cli": "4.10.1", + "mjml-core": "4.10.1", + "mjml-migrate": "4.10.1", + "mjml-preset-core": "4.10.1", + "mjml-validator": "4.10.1" + }, + "bin": { + "mjml": "bin/mjml" + } + }, + "node_modules/mjml-accordion": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.10.1.tgz", + "integrity": "sha512-wQ2PHsiuq3wxsumb78T7gWimB9aQXWP1yDQrQiLn+hmARiLOv9KOn96ZffM4nWyNlDM0AsWWm9fpLgv1RwI8wQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-body": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.10.1.tgz", + "integrity": "sha512-6+v/m+PhTkm8NZYim1g2H0GsQ9sydZQZiaGCnzSpKJL6HXMYHqckdUc/yvgph86/XPRDTv2dIv/tvgJ5dBvFlA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-button": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.10.1.tgz", + "integrity": "sha512-3lmez3NZt1TJjE+HLZO10q9dfminH5JtTEV2m9Yf/gXRoT+vpD7XFs5vrAXVhMh879Unc3pxY8ghFr0/8JLBgQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-carousel": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.10.1.tgz", + "integrity": "sha512-5n9LKP0KANRCoZDgT7jJCMiKlWr26idy1Sc2PunJ71164/lE6HKhSvMISNEdxDm+ZTj4Y2vDeobcc3zviQRkcw==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-cli": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.10.1.tgz", + "integrity": "sha512-M/N704fblgiJOqyqD6PoEi0F4ILnb5PLFsRF0BE8NNoCpQz0WnnnUjuCnPBfgCsz/rVxBrSXYpGNrpViCkgftQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "chokidar": "^3.0.0", + "glob": "^7.1.1", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "lodash": "^4.17.15", + "mjml-core": "4.10.1", + "mjml-migrate": "4.10.1", + "mjml-parser-xml": "4.10.1", + "mjml-validator": "4.10.1", + "yargs": "^16.1.0" + }, + "bin": { + "mjml-cli": "bin/mjml" + } + }, + "node_modules/mjml-column": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.10.1.tgz", + "integrity": "sha512-ajn2YHc3rWXhXYsJiOvYnHBWbSB+ep1dTs+qe2uhxq9h8BdvG9bxh5UZeN3do7IEwqZIeA7lFKeWZyu07LapCQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-core": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.10.1.tgz", + "integrity": "sha512-2RsFeWteelaaijD6dDFsvpgc/Zt5caKmUCr1sI3u7gIpH17LEjS5+CcSTEUwAOyAztUxpNfdotuWs3W0i2YyCA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "cheerio": "1.0.0-rc.10", + "detect-node": "2.0.4", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "juice": "^7.0.0", + "lodash": "^4.17.15", + "mjml-migrate": "4.10.1", + "mjml-parser-xml": "4.10.1", + "mjml-validator": "4.10.1" + } + }, + "node_modules/mjml-divider": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.10.1.tgz", + "integrity": "sha512-k3Rs+Owa9zdS49LbSGA+KkI9XFnAjJpINCYSfwp0p05HP+80jZAVIyb8/oMVjwzcM3CCPQhqSxg6WSuLMDfezg==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-group": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.10.1.tgz", + "integrity": "sha512-uW5lIA3vRYqyUU7rzv2rMcUZkPkol4l4GJPnDvx5Pm45H9ogD8GgdhlPUq95cKRGEOqxj9ytFXqKrb1SlfDi3g==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.10.1.tgz", + "integrity": "sha512-NYnITF3yZvN4pemiJISW7rINjaQtVmtFwNROleHRBNj/7GleklSo6cMOYljhJ95qzUyFlEVPbO54+znt1IlQHw==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-attributes": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.10.1.tgz", + "integrity": "sha512-o6Peu/NcoQ45YTIfuVrE5QDutl8Zi+Zp7owkF6yDFPqQfVR8QCTQ/JS+3Z0bI/HRXoljV6O7eCBA6HbDdvMiaQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-breakpoint": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.10.1.tgz", + "integrity": "sha512-2QJxmrQqB0N+Crfn+Cguq5eeL8YQ3y4g2K3UQ1d7dB0rEiwWN5x9gb4iOrrPTagepdYiaELJo9RqwR26WGw+9A==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-font": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.10.1.tgz", + "integrity": "sha512-WjEyBneeyRaeEnW/iqfOMLGvkpSSijqHQxk/z6yVVQ+fEcZ6kOZFPIVDrXSgLUpPso0GV46ngde57zWuBYuTUQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-html-attributes": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.10.1.tgz", + "integrity": "sha512-ZT5DPfCauY0N6JR4ouJaJ3dYiUDbsXWE27A5bGTUNF19fl59571z/lfTgCUnW4veXmG4n4JvOQYdw8QLotn7/w==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-preview": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.10.1.tgz", + "integrity": "sha512-aeWHNiIAiREraDWwdniqWt3Vy97Ao/hxu46FJFwLn7q4Za3ZevxeHzzIoPgkGB8qaOSKHeyYDLHwhzLqnQAdKw==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-style": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.10.1.tgz", + "integrity": "sha512-iCY5JsxJU9wiqh4A20CxeAv2MLqUBKotDS6V4lD16QVR2U1GDc7ZfP7rU8bL8ULE/589RxmkMq/+w3W5Fyx56g==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-head-title": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.10.1.tgz", + "integrity": "sha512-rw18SV3X0mGi+59cZUFxrsXKFhK0sO1NniwKyxAtb/9cjlHiMbiXYeSOaw8Yg4Ee++C37xOd5hWCCxXUj09kFw==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-hero": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.10.1.tgz", + "integrity": "sha512-3MozfbGnF7XbVzBJ1iz6F7nTDnJUZTRgaIbPhFQXDCbJ33LN6IPPS1+22iQnlZQeTG9N4SpJLjlG2W8UQp7rew==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-image": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.10.1.tgz", + "integrity": "sha512-LZr49qbXDa/i9wM3iBOdwF9zndYn/xTHaofUn3rUxVmybfGLmr/N5fc84ZGMs4kBWYz8kuHodjOnaY/9g58pyg==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-migrate": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.10.1.tgz", + "integrity": "sha512-RfUUqW9oqxp/42EVVygpu7v1/TX0TksJS3+7cAAuMSh8WsXQGYaNDDpFjItQapMDYfOVT/0Uby1L8PiuhQtx+g==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "js-beautify": "^1.6.14", + "lodash": "^4.17.15", + "mjml-core": "4.10.1", + "mjml-parser-xml": "4.10.1", + "yargs": "^16.1.0" + }, + "bin": { + "migrate": "lib/cli.js" + } + }, + "node_modules/mjml-navbar": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.10.1.tgz", + "integrity": "sha512-Fu6/1WxXFgY478OINmiCrB3tE2c2uaEpXNS0ac2EbIytaM7/azQ58+Y07jfie1UXM6cjHAb5ZWOTjvJoPPOdag==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-parser-xml": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.10.1.tgz", + "integrity": "sha512-dQW7efbPTXY9cgEshxefiEQ6lcWXp1yADjfv6hWYhcWlpeBfyZ6NBDL8aoRoem+5+avMSzn1tP1oRvedlSY/9Q==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "detect-node": "2.0.4", + "htmlparser2": "^4.1.0", + "lodash": "^4.17.15" + } + }, + "node_modules/mjml-parser-xml/node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/mjml-parser-xml/node_modules/htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "node_modules/mjml-preset-core": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.10.1.tgz", + "integrity": "sha512-zAD72N3xb5vxOedd446g1lAvMeh57JZ5HDUUFNB473QVvu7HgX2OShykwsgyzgYgKXE3MBhms8nr1jv55SnPuA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "mjml-accordion": "4.10.1", + "mjml-body": "4.10.1", + "mjml-button": "4.10.1", + "mjml-carousel": "4.10.1", + "mjml-column": "4.10.1", + "mjml-divider": "4.10.1", + "mjml-group": "4.10.1", + "mjml-head": "4.10.1", + "mjml-head-attributes": "4.10.1", + "mjml-head-breakpoint": "4.10.1", + "mjml-head-font": "4.10.1", + "mjml-head-html-attributes": "4.10.1", + "mjml-head-preview": "4.10.1", + "mjml-head-style": "4.10.1", + "mjml-head-title": "4.10.1", + "mjml-hero": "4.10.1", + "mjml-image": "4.10.1", + "mjml-navbar": "4.10.1", + "mjml-raw": "4.10.1", + "mjml-section": "4.10.1", + "mjml-social": "4.10.1", + "mjml-spacer": "4.10.1", + "mjml-table": "4.10.1", + "mjml-text": "4.10.1", + "mjml-wrapper": "4.10.1" + } + }, + "node_modules/mjml-raw": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.10.1.tgz", + "integrity": "sha512-CgVn5E9c4uEvn10JMoOLrbcKLpaN1JAyl0d1M01v2kp1iG6VnfMv0BydliC7nZ4kHk7+bJ51XjkMBl9k+KDZYA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-section": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.10.1.tgz", + "integrity": "sha512-9QC5tyJ4hgbA/lRLZRNgIh866/VTfLc7+ucKkaWnteeF/CCxjqTwcYrLPbR5HKEMSjVd5/T17SOVOB6jv/VIdg==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-social": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.10.1.tgz", + "integrity": "sha512-YuPjJF60oXQ47cd0gtJfy8SZBBBM8HV7pFwIuD1NIKdTU6qPZj38X81ZKPPuvmD1td+FVG/W/mySzuuH1hZkWQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-spacer": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.10.1.tgz", + "integrity": "sha512-/wgxbrAIGrjpB5Z3KZUKDliQ/bdUsEouXgbMjRqoPfgskVV6ocrSLMDjWT8XEpYPSKb5T4p3dlWn8XKKl1nrOw==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-table": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.10.1.tgz", + "integrity": "sha512-bfztBF/leXqbVHcOUiQu4zaSlW7i7lE2q0mb8gPHPRbh9cPzwetk5pYh9Gc7PiMpodvzpAYR2OeaQS0Z4FfjKg==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-text": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.10.1.tgz", + "integrity": "sha512-SjB6U3O6TjkaeonQ85+BKfIQUGMf4gybS1QuI2ULlAMPlNYpmkNBhPzlXNECWUG1OETg1HgD6WqEYBG8Dd970A==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1" + } + }, + "node_modules/mjml-validator": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.10.1.tgz", + "integrity": "sha512-tYnRLtupjAj82Do9gb2Y8hWGSGz6nTLV6csia11JubhLoykJNS3JnGW2CPZ/Y+zWNUxJMNHkgHnxAPwSlmX6dQ==", + "dependencies": { + "@babel/runtime": "^7.8.7" + } + }, + "node_modules/mjml-wrapper": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.10.1.tgz", + "integrity": "sha512-z0ewwxWPZAnIMKqsRCHh/jjsgPNcMO4Yej32LLait6IOAiUmo2hWLhrDmSFY69NrzuxxQPBI7tZ8G5LUbaH/EQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "lodash": "^4.17.15", + "mjml-core": "4.10.1", + "mjml-section": "4.10.1" + } + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "node_modules/slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=", + "engines": { + "node": "*" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/uglify-js": { + "version": "3.13.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.10.tgz", + "integrity": "sha512-57H3ACYFXeo1IaZ1w02sfA71wI60MGco/IQFjOqK+WtKoprh7Go2/yvd2HPtoJILO2Or84ncLccI4xoHMTSbGg==", + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "node_modules/valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/web-resource-inliner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz", + "integrity": "sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==", + "dependencies": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^4.0.0", + "mime": "^2.4.6", + "node-fetch": "^2.6.0", + "valid-data-url": "^3.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web-resource-inliner/node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/web-resource-inliner/node_modules/htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "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==", + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "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==", + "engines": { + "node": ">=10" + } + } + }, "dependencies": { "@babel/runtime": { "version": "7.14.6", diff --git a/src/main/dist/Dockerfile b/src/main/dist/Dockerfile index f8713c944f..31b995f6e2 100644 --- a/src/main/dist/Dockerfile +++ b/src/main/dist/Dockerfile @@ -5,18 +5,18 @@ # - https://august.nagro.us/small-java.html # -FROM azul/zulu-openjdk-alpine:15.0.2 as zulu +FROM azul/zulu-openjdk-alpine:17 as zulu RUN $JAVA_HOME/bin/jlink --compress=1 --strip-java-debug-attributes --no-header-files --no-man-pages \ --module-path $JAVA_HOME/jmods \ - # see https://github.com/ben-manes/caffeine/issues/273 + # see https://github.com/ben-manes/caffeine/issues/273 TODO investigate if we can remove jdk.unsupported # see https://docs.oracle.com/en/java/javase/11/security/oracle-providers.html#GUID-9224B90B-7B2F-41F9-BB96-C0A1B6A0FEAA --add-modules java.desktop,java.logging,java.sql,java.management,java.naming,jdk.unsupported,jdk.crypto.ec,java.net.http,jdk.localedata \ --include-locales en,it,es,nl,fr,de,ro,pt,tr,pl,da,bg,sv \ --output /jlinked -FROM alpine:3.12 -LABEL org.opencontainers.image.source https://github.com/alfio-event/alf.io +FROM alpine:3.15 +LABEL org.opencontainers.image.source=https://github.com/alfio-event/alf.io COPY --from=zulu /jlinked /opt/jdk/ diff --git a/src/main/java/alfio/config/BaseConfiguration.java b/src/main/java/alfio/config/BaseConfiguration.java index 9cf3122667..1dffe3ea5f 100644 --- a/src/main/java/alfio/config/BaseConfiguration.java +++ b/src/main/java/alfio/config/BaseConfiguration.java @@ -56,12 +56,16 @@ ConfigurationManager configurationManager(ConfigurationRepository configurationR cache); } - @Bean - ObjectMapper objectMapper() { + public static ObjectMapper buildObjectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); return mapper; } + + @Bean + ObjectMapper objectMapper() { + return buildObjectMapper(); + } } diff --git a/src/main/java/alfio/config/ConfigurationStatusChecker.java b/src/main/java/alfio/config/ConfigurationStatusChecker.java index 77521b450b..7173da429b 100644 --- a/src/main/java/alfio/config/ConfigurationStatusChecker.java +++ b/src/main/java/alfio/config/ConfigurationStatusChecker.java @@ -25,7 +25,8 @@ import alfio.repository.user.AuthorityRepository; import alfio.repository.user.UserRepository; import alfio.util.PasswordGenerator; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationListener; @@ -37,9 +38,10 @@ import static java.util.Optional.ofNullable; @Component -@Log4j2 public class ConfigurationStatusChecker implements ApplicationListener { + private static final Logger log = LoggerFactory.getLogger(ConfigurationStatusChecker.class); + private final ConfigurationManager configurationManager; private final UserRepository userRepository; private final AuthorityRepository authorityRepository; diff --git a/src/main/java/alfio/config/DataSourceConfiguration.java b/src/main/java/alfio/config/DataSourceConfiguration.java index 7b722c88ad..a6d798bbcb 100644 --- a/src/main/java/alfio/config/DataSourceConfiguration.java +++ b/src/main/java/alfio/config/DataSourceConfiguration.java @@ -22,18 +22,12 @@ import alfio.config.support.PlatformProvider; import alfio.extension.ExtensionService; import alfio.job.Jobs; -import alfio.job.executor.AssignTicketToSubscriberJobExecutor; -import alfio.job.executor.BillingDocumentJobExecutor; -import alfio.job.executor.ReservationJobExecutor; -import alfio.job.executor.RetryFailedExtensionJobExecutor; +import alfio.job.executor.*; import alfio.manager.*; import alfio.manager.i18n.MessageSourceManager; import alfio.manager.system.AdminJobManager; import alfio.manager.system.ConfigurationManager; -import alfio.repository.EventDeleterRepository; -import alfio.repository.EventRepository; -import alfio.repository.SubscriptionRepository; -import alfio.repository.TicketCategoryRepository; +import alfio.repository.*; import alfio.repository.system.AdminJobQueueRepository; import alfio.repository.system.ConfigurationRepository; import alfio.repository.user.OrganizationRepository; @@ -47,10 +41,11 @@ import ch.digitalfondue.npjt.mapper.ColumnMapperFactory; import ch.digitalfondue.npjt.mapper.ParameterConverter; import com.zaxxer.hikari.HikariDataSource; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.*; import org.springframework.core.env.Environment; import org.springframework.jdbc.core.JdbcTemplate; @@ -84,10 +79,11 @@ @EnableScheduling @EnableAsync @ComponentScan(basePackages = {"alfio.manager", "alfio.extension"}) -@Log4j2 @EnableNpjt(basePackages = "alfio.repository") public class DataSourceConfiguration { + private static final Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class); + private static final Set PLATFORM_PROVIDERS = EnumSet.complementOf(EnumSet.of(PlatformProvider.DEFAULT)); @Bean @@ -255,9 +251,10 @@ AdminJobManager adminJobManager(AdminJobQueueRepository adminJobQueueRepository, ReservationJobExecutor reservationJobExecutor, BillingDocumentJobExecutor billingDocumentJobExecutor, AssignTicketToSubscriberJobExecutor assignTicketToSubscriberJobExecutor, - RetryFailedExtensionJobExecutor retryFailedExtensionJobExecutor) { + RetryFailedExtensionJobExecutor retryFailedExtensionJobExecutor, + RetryFailedReservationConfirmationExecutor retryFailedReservationConfirmationExecutor) { return new AdminJobManager( - List.of(reservationJobExecutor, billingDocumentJobExecutor, assignTicketToSubscriberJobExecutor, retryFailedExtensionJobExecutor), + List.of(reservationJobExecutor, billingDocumentJobExecutor, assignTicketToSubscriberJobExecutor, retryFailedExtensionJobExecutor, retryFailedReservationConfirmationExecutor), adminJobQueueRepository, transactionManager, clockProvider); @@ -297,16 +294,21 @@ RetryFailedExtensionJobExecutor retryFailedExtensionJobExecutor(ExtensionService return new RetryFailedExtensionJobExecutor(extensionService); } + @Bean + RetryFailedReservationConfirmationExecutor retryFailedReservationConfirmationExecutor(ReservationFinalizer reservationFinalizer, Json json) { + return new RetryFailedReservationConfirmationExecutor(reservationFinalizer, json); + } + @Bean @Profile(Initializer.PROFILE_DEMO) DemoModeDataManager demoModeDataManager(UserRepository userRepository, UserOrganizationRepository userOrganizationRepository, - OrganizationRepository organizationRepository, EventDeleterRepository eventDeleterRepository, EventRepository eventRepository, - ConfigurationManager configurationManager) { - return new DemoModeDataManager(userRepository, userOrganizationRepository, organizationRepository, - eventDeleterRepository, eventRepository, configurationManager); + ConfigurationManager configurationManager, + OrganizationDeleterRepository organizationDeleterRepository) { + return new DemoModeDataManager(userRepository, userOrganizationRepository, + eventDeleterRepository, eventRepository, configurationManager, organizationDeleterRepository); } /** diff --git a/src/main/java/alfio/config/Initializer.java b/src/main/java/alfio/config/Initializer.java index 824ca60ff0..6cc0892b4b 100644 --- a/src/main/java/alfio/config/Initializer.java +++ b/src/main/java/alfio/config/Initializer.java @@ -42,6 +42,8 @@ public class Initializer extends AbstractAnnotationConfigDispatcherServletInitia public static final String PROFILE_DEMO = "demo"; public static final String PROFILE_OPENID = "openid"; public static final String PROFILE_DISABLE_JOBS = "disable-jobs"; + public static final String API_V2_PUBLIC_PATH = "/api/v2/public/"; + public static final String XSRF_TOKEN = "XSRF-TOKEN"; private Environment environment; @Override diff --git a/src/main/java/alfio/config/MvcConfiguration.java b/src/main/java/alfio/config/MvcConfiguration.java index 1e089e91e5..4ca3be85cc 100644 --- a/src/main/java/alfio/config/MvcConfiguration.java +++ b/src/main/java/alfio/config/MvcConfiguration.java @@ -28,7 +28,12 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; +import org.springframework.session.web.http.CookieHttpSessionIdResolver; +import org.springframework.session.web.http.HeaderHttpSessionIdResolver; +import org.springframework.session.web.http.HttpSessionIdResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -37,27 +42,29 @@ import org.springframework.web.servlet.view.AbstractUrlBasedView; import org.springframework.web.servlet.view.UrlBasedViewResolver; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.time.Duration; import java.util.Collections; import java.util.List; +import static alfio.config.Initializer.API_V2_PUBLIC_PATH; + + @Configuration(proxyBeanMethods = false) @ComponentScan(basePackages = {"alfio.controller", "alfio.config"}) @EnableWebMvc -@EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 4 * 60 * 60) //4h +@EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 4 * 60 * 60, tableName = "ALFIO_SPRING_SESSION") //4h public class MvcConfiguration implements WebMvcConfigurer { private final Environment environment; - private final String frontendVersion; private final String alfioVersion; private final ObjectMapper objectMapper; public MvcConfiguration(Environment environment, - @Value("${alfio.frontend.version}") String frontendVersion, @Value("${alfio.version}") String alfioVersion, ObjectMapper objectMapper) { this.environment = environment; - this.frontendVersion = frontendVersion; this.alfioVersion = alfioVersion; this.objectMapper = objectMapper; } @@ -83,21 +90,16 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) { .addResourceLocations("/resources/images/") .setCachePeriod(cacheMinutes * 60) .setCacheControl(defaultCacheControl); - // - registry - .addResourceHandler("/webjars/**") - .addResourceLocations("/webjars/") - .setCacheControl(defaultCacheControl); - registry.addResourceHandler("/assets/**") - .addResourceLocations("/webjars/alfio-public-frontend/" + frontendVersion + "/alfio-public-frontend/assets/") + registry.addResourceHandler("/frontend-public/**") + .addResourceLocations("/resources/alfio-public-frontend/") .setCachePeriod(cacheMinutes * 60) - .setCacheControl(defaultCacheControl); + .setCacheControl(CacheControl.maxAge(Duration.ofDays(60))); - registry.addResourceHandler("/*.js") - .addResourceLocations("/webjars/alfio-public-frontend/" + frontendVersion + "/alfio-public-frontend/") + registry.addResourceHandler("/frontend-admin/**") + .addResourceLocations("/resources/alfio-admin-frontend/") .setCachePeriod(cacheMinutes * 60) - .setCacheControl(defaultCacheControl); + .setCacheControl(CacheControl.maxAge(Duration.ofDays(60))); } @@ -128,4 +130,45 @@ public ViewResolver viewResolver() { resolver.setViewClass(AbstractUrlBasedView.class); return resolver; } + + @Bean + public SpringSessionBackedSessionRegistry sessionRegistry(FindByIndexNameSessionRepository sessionRepository) { + return new SpringSessionBackedSessionRegistry<>(sessionRepository); + } + + @Bean + public HttpSessionIdResolver httpSessionIdResolver() { + var publicSessionIdResolver = HeaderHttpSessionIdResolver.xAuthToken(); + var adminSessionIdResolver = new CookieHttpSessionIdResolver(); + return new HttpSessionIdResolver() { + @Override + public List resolveSessionIds(HttpServletRequest request) { + return isPublic(request) ? publicSessionIdResolver.resolveSessionIds(request) + : adminSessionIdResolver.resolveSessionIds(request); + } + + @Override + public void setSessionId(HttpServletRequest request, HttpServletResponse response, String sessionId) { + if (isPublic(request)) { + publicSessionIdResolver.setSessionId(request, response, sessionId); + } else { + adminSessionIdResolver.setSessionId(request, response, sessionId); + } + } + + @Override + public void expireSession(HttpServletRequest request, HttpServletResponse response) { + if (isPublic(request)) { + publicSessionIdResolver.expireSession(request, response); + } else { + adminSessionIdResolver.expireSession(request, response); + } + } + + private static boolean isPublic(HttpServletRequest request) { + var requestURI = request.getRequestURI(); + return requestURI.startsWith(API_V2_PUBLIC_PATH); + } + }; + } } diff --git a/src/main/java/alfio/config/RoleAndOrganizationsTransactionPreparer.java b/src/main/java/alfio/config/RoleAndOrganizationsTransactionPreparer.java index c5dd5180bf..f553abe9cc 100644 --- a/src/main/java/alfio/config/RoleAndOrganizationsTransactionPreparer.java +++ b/src/main/java/alfio/config/RoleAndOrganizationsTransactionPreparer.java @@ -17,7 +17,8 @@ package alfio.config; import alfio.config.authentication.support.OpenIdAlfioAuthentication; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -34,9 +35,15 @@ import java.util.TreeSet; import java.util.stream.Collectors; -@Log4j2 +import static alfio.config.authentication.support.AuthenticationConstants.ADMIN; +import static alfio.config.authentication.support.AuthenticationConstants.SYSTEM_API_CLIENT; + class RoleAndOrganizationsTransactionPreparer { + private static final Logger log = LoggerFactory.getLogger(RoleAndOrganizationsTransactionPreparer.class); + + private RoleAndOrganizationsTransactionPreparer() {} + private static final OrRequestMatcher IS_PUBLIC_URLS = new OrRequestMatcher( new AntPathRequestMatcher("/resources/**"), new AntPathRequestMatcher("/webjars/**"), @@ -82,7 +89,7 @@ private static boolean isAdmin() { return SecurityContextHolder.getContext().getAuthentication() .getAuthorities().stream() .map(GrantedAuthority::getAuthority) - .anyMatch("ROLE_ADMIN"::equals); + .anyMatch(authority -> authority.equals("ROLE_" + SYSTEM_API_CLIENT) || authority.equals("ROLE_" + ADMIN)); } return false; } diff --git a/src/main/java/alfio/config/SpringBootInitializer.java b/src/main/java/alfio/config/SpringBootInitializer.java index 0654a9f16c..3ed7dd51ce 100644 --- a/src/main/java/alfio/config/SpringBootInitializer.java +++ b/src/main/java/alfio/config/SpringBootInitializer.java @@ -21,49 +21,33 @@ import com.openhtmltopdf.util.XRLog; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Profiles; -import org.springframework.web.context.WebApplicationContext; import org.springframework.web.filter.CharacterEncodingFilter; import javax.servlet.Filter; -import javax.servlet.SessionCookieConfig; import java.time.Clock; import java.util.logging.Level; -import static org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext; - @EnableAutoConfiguration(exclude = {org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration.class, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.class, org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.class, org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration.class, org.springframework.boot.autoconfigure.session.SessionAutoConfiguration.class, org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration.class, - org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration.class}) + org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration.class, + org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.class +}) @EnableConfigurationProperties(ExternalConfiguration.class) @Configuration(proxyBeanMethods = false) @Profile(Initializer.PROFILE_SPRING_BOOT) public class SpringBootInitializer { - @Bean - public ServletContextInitializer servletContextInitializer() { - return servletContext -> { - WebApplicationContext ctx = getRequiredWebApplicationContext(servletContext); - ConfigurableEnvironment environment = ctx.getBean(ConfigurableEnvironment.class); - SessionCookieConfig config = servletContext.getSessionCookieConfig(); - config.setHttpOnly(true); - config.setSecure(environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_LIVE))); - // force log initialization, then disable it - XRLog.setLevel(XRLog.EXCEPTION, Level.WARNING); - XRLog.setLoggingEnabled(false); - }; - } - @Bean public Filter characterEncodingFilter() { CharacterEncodingFilter cef = new CharacterEncodingFilter(); @@ -76,4 +60,16 @@ public Filter characterEncodingFilter() { public ClockProvider clockProvider() { return ClockProvider.init(Clock.systemUTC()); } + + @Bean + public WebServerFactoryCustomizer applicationCookieSameSiteSupplier() { + return factory -> { + factory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofStrict()); + factory.addInitializers(servletContext -> { + // force log initialization, then disable it + XRLog.setLevel(XRLog.EXCEPTION, Level.WARNING); + XRLog.setLoggingEnabled(false); + }); + }; + } } diff --git a/src/main/java/alfio/config/SpringBootLauncher.java b/src/main/java/alfio/config/SpringBootLauncher.java index 5fc52602c1..fdc9d9de60 100644 --- a/src/main/java/alfio/config/SpringBootLauncher.java +++ b/src/main/java/alfio/config/SpringBootLauncher.java @@ -17,7 +17,8 @@ package alfio.config; import alfio.util.DefaultExceptionHandler; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; @@ -25,9 +26,10 @@ import java.util.ArrayList; import java.util.List; -@Log4j2 public class SpringBootLauncher { + private static final Logger log = LoggerFactory.getLogger(SpringBootLauncher.class); + /** * Entry point for spring boot * @param args original arguments diff --git a/src/main/java/alfio/config/WebSecurityConfig.java b/src/main/java/alfio/config/WebSecurityConfig.java index 992f91cc77..51ab22515c 100644 --- a/src/main/java/alfio/config/WebSecurityConfig.java +++ b/src/main/java/alfio/config/WebSecurityConfig.java @@ -26,7 +26,6 @@ import alfio.repository.user.UserRepository; import alfio.repository.user.join.UserOrganizationRepository; import alfio.util.Json; -import lombok.extern.log4j.Log4j2; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @@ -39,9 +38,10 @@ import java.net.http.HttpClient; +import static alfio.config.Initializer.PROFILE_OPENID; + @Configuration(proxyBeanMethods = false) @EnableWebSecurity -@Log4j2 public class WebSecurityConfig { public static final String CSRF_PARAM_NAME = "_csrf"; @@ -56,7 +56,7 @@ public CsrfTokenRepository getCsrfTokenRepository() { } @Bean - @Profile("openid") + @Profile(PROFILE_OPENID) public AdminOpenIdAuthenticationManager adminOpenIdAuthenticationManager(Environment environment, HttpClient httpClient, ConfigurationManager configurationManager, diff --git a/src/main/java/alfio/config/authentication/APITokenAuthWebSecurity.java b/src/main/java/alfio/config/authentication/APITokenAuthWebSecurity.java index 8d61f7df4c..669f84df41 100644 --- a/src/main/java/alfio/config/authentication/APITokenAuthWebSecurity.java +++ b/src/main/java/alfio/config/authentication/APITokenAuthWebSecurity.java @@ -16,81 +16,111 @@ */ package alfio.config.authentication; -import alfio.config.authentication.support.APIKeyAuthFilter; -import alfio.config.authentication.support.APITokenAuthentication; -import alfio.config.authentication.support.RequestTypeMatchers; -import alfio.config.authentication.support.WrongAccountTypeException; +import alfio.config.authentication.support.*; +import alfio.model.system.ConfigurationKeys; import alfio.model.user.User; +import alfio.repository.system.ConfigurationRepository; import alfio.repository.user.AuthorityRepository; import alfio.repository.user.UserRepository; import alfio.util.ClockProvider; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.web.SecurityFilterChain; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.time.ZonedDateTime; -import java.util.stream.Collectors; +import java.util.List; -import static alfio.config.authentication.AuthenticationConstants.*; +import static alfio.config.authentication.support.AuthenticationConstants.*; @Configuration(proxyBeanMethods = false) @Order(0) -public class APITokenAuthWebSecurity extends WebSecurityConfigurerAdapter { +public class APITokenAuthWebSecurity { + public static final String API_KEY = "Api key "; private final UserRepository userRepository; private final AuthorityRepository authorityRepository; + private final ConfigurationRepository configurationRepository; public APITokenAuthWebSecurity(UserRepository userRepository, - AuthorityRepository authorityRepository) { + AuthorityRepository authorityRepository, + ConfigurationRepository configurationRepository) { this.userRepository = userRepository; this.authorityRepository = authorityRepository; + this.configurationRepository = configurationRepository; } //https://stackoverflow.com/a/48448901 - @Override - protected void configure(HttpSecurity http) throws Exception { + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { APIKeyAuthFilter filter = new APIKeyAuthFilter(); filter.setAuthenticationManager(authentication -> { // String apiKey = (String) authentication.getPrincipal(); + + // check if API Key is system + var systemApiKeyOptional = configurationRepository.findOptionalByKey(ConfigurationKeys.SYSTEM_API_KEY.name()); + + if (systemApiKeyOptional.isPresent() && apiKeyMatches(apiKey, systemApiKeyOptional.get())) { + return new APITokenAuthentication( + authentication.getPrincipal(), + authentication.getCredentials(), + List.of(new SimpleGrantedAuthority("ROLE_" + SYSTEM_API_CLIENT))); + } + //check if user type -> - User user = userRepository.findByUsername(apiKey).orElseThrow(() -> new BadCredentialsException("Api key " + apiKey + " don't exists")); + User user = userRepository.findByUsername(apiKey).orElseThrow(() -> new BadCredentialsException(API_KEY + apiKey + " don't exists")); if (!user.isEnabled()) { - throw new DisabledException("Api key " + apiKey + " is disabled"); + throw new DisabledException(API_KEY + apiKey + " is disabled"); } if (User.Type.API_KEY != user.getType()) { throw new WrongAccountTypeException("Wrong account type for username " + apiKey); } if (!user.isCurrentlyValid(ZonedDateTime.now(ClockProvider.clock()))) { - throw new DisabledException("Api key " + apiKey + " is expired"); + throw new DisabledException(API_KEY + apiKey + " is expired"); } return new APITokenAuthentication( authentication.getPrincipal(), authentication.getCredentials(), - authorityRepository.findRoles(apiKey).stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())); + authorityRepository.findRoles(apiKey).stream().map(SimpleGrantedAuthority::new).toList()); }); - http.requestMatcher(RequestTypeMatchers::isTokenAuthentication) + return http.requestMatcher(RequestTypeMatchers::isTokenAuthentication) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and().csrf().disable() - .authorizeRequests() + .authorizeRequests(APITokenAuthWebSecurity::configureMatchers) + .addFilter(filter) + .build(); + } + + private static void configureMatchers(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry auth) { + auth.antMatchers(ADMIN_PUBLIC_API + "/system/**").hasRole(SYSTEM_API_CLIENT) .antMatchers(ADMIN_PUBLIC_API + "/**").hasRole(API_CLIENT) + .antMatchers(ADMIN_API + "/check-in/event/*/attendees").hasRole(SUPERVISOR) + .antMatchers(ADMIN_API + "/check-in/*/label-layout").hasAnyRole(OPERATOR, SUPERVISOR, SPONSOR) .antMatchers(ADMIN_API + "/check-in/**").hasAnyRole(OPERATOR, SUPERVISOR) - .antMatchers(HttpMethod.GET, ADMIN_API + "/events").hasAnyRole(OPERATOR, SUPERVISOR, AuthenticationConstants.SPONSOR) + .antMatchers(HttpMethod.GET, ADMIN_API + "/events").hasAnyRole(OPERATOR, SUPERVISOR, SPONSOR) .antMatchers(HttpMethod.GET, ADMIN_API + "/user-type", ADMIN_API + "/user/details").hasAnyRole(OPERATOR, SUPERVISOR, AuthenticationConstants.SPONSOR) .antMatchers(ADMIN_API + "/**").denyAll() - .antMatchers(HttpMethod.POST, "/api/attendees/sponsor-scan").hasRole(AuthenticationConstants.SPONSOR) + .antMatchers(HttpMethod.POST, "/api/attendees/sponsor-scan").hasRole(SPONSOR) .antMatchers(HttpMethod.GET, "/api/attendees/*/ticket/*").hasAnyRole(OPERATOR, SUPERVISOR, API_CLIENT) - .antMatchers("/**").authenticated() - .and().addFilter(filter); + .antMatchers("/**").authenticated(); + } + + private static boolean apiKeyMatches(String input, alfio.model.system.Configuration systemApiKeyConfiguration) { + return MessageDigest.isEqual(input.getBytes(StandardCharsets.UTF_8), + systemApiKeyConfiguration.getValue().getBytes(StandardCharsets.UTF_8)); } } diff --git a/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java b/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java index e0cd288a29..39e7bd12ce 100644 --- a/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java +++ b/src/main/java/alfio/config/authentication/AbstractFormBasedWebSecurity.java @@ -23,17 +23,21 @@ import alfio.manager.openid.PublicOpenIdAuthenticationManager; import alfio.manager.system.ConfigurationManager; import alfio.manager.user.UserManager; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jetty.http.HttpCookie; +import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.JdbcUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.csrf.CsrfToken; @@ -41,20 +45,45 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.NegatedRequestMatcher; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; +import org.springframework.session.FindByIndexNameSessionRepository; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; +import javax.servlet.Filter; import javax.servlet.RequestDispatcher; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; +import java.util.List; import java.util.function.Predicate; import java.util.regex.Pattern; -import static alfio.config.authentication.AuthenticationConstants.*; +import static alfio.config.Initializer.API_V2_PUBLIC_PATH; +import static alfio.config.Initializer.XSRF_TOKEN; +import static alfio.config.authentication.support.AuthenticationConstants.*; import static alfio.config.authentication.support.OpenIdAuthenticationFilter.*; -@AllArgsConstructor(access = AccessLevel.PROTECTED) -abstract class AbstractFormBasedWebSecurity extends WebSecurityConfigurerAdapter { +abstract class AbstractFormBasedWebSecurity { + public static final String AUTHENTICATE = "/authenticate"; + private static final String[] OWNERSHIP_REQUIRED = new String[]{ + ADMIN_API + "/overridable-template", + ADMIN_API + "/additional-services", + ADMIN_API + "/events/*/additional-field", + ADMIN_API + "/event/*/additional-services/", + ADMIN_API + "/overridable-template/", + ADMIN_API + "/events/*/promo-code", + ADMIN_API + "/reservation/event/*/reservations/list", + ADMIN_API + "/event/*/email/", + ADMIN_API + "/event/*/waiting-queue/load", + ADMIN_API + "/events/*/pending-payments", + ADMIN_API + "/events/*/export", + ADMIN_API + "/events/*/sponsor-scan/export", + ADMIN_API + "/events/*/invoices/**", + ADMIN_API + "/reservation/*/*/*/audit", + ADMIN_API + "/subscription/*/email/", + ADMIN_API + "/organization/*/subscription/**", + ADMIN_API + "/reservation/subscription/**" + }; private final Environment environment; private final UserManager userManager; private final RecaptchaService recaptchaService; @@ -63,149 +92,187 @@ abstract class AbstractFormBasedWebSecurity extends WebSecurityConfigurerAdapter private final DataSource dataSource; private final PasswordEncoder passwordEncoder; private final PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager; + private final SpringSessionBackedSessionRegistry sessionRegistry; - @Override - public void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.jdbcAuthentication().dataSource(dataSource) - .usersByUsernameQuery("select username, password, enabled from ba_user where username = ?") - .authoritiesByUsernameQuery("select username, role from authority where username = ?") - .passwordEncoder(passwordEncoder) - .and() - .authenticationProvider(new OpenIdAuthenticationProvider()); + protected AbstractFormBasedWebSecurity(Environment environment, + UserManager userManager, + RecaptchaService recaptchaService, + ConfigurationManager configurationManager, + CsrfTokenRepository csrfTokenRepository, + DataSource dataSource, + PasswordEncoder passwordEncoder, + PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager, + SpringSessionBackedSessionRegistry sessionRegistry) { + this.environment = environment; + this.userManager = userManager; + this.recaptchaService = recaptchaService; + this.configurationManager = configurationManager; + this.csrfTokenRepository = csrfTokenRepository; + this.dataSource = dataSource; + this.passwordEncoder = passwordEncoder; + this.publicOpenIdAuthenticationManager = publicOpenIdAuthenticationManager; + this.sessionRegistry = sessionRegistry; } - @Override - protected void configure(HttpSecurity http) throws Exception { - if (environment.acceptsProfiles(Profiles.of("!" + Initializer.PROFILE_DEV))) { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + if (environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_LIVE))) { http.requiresChannel().antMatchers("/healthz").requiresInsecure() .and() .requiresChannel().mvcMatchers("/**").requiresSecure(); } - CsrfConfigurer configurer = - http.exceptionHandling() - .accessDeniedHandler((request, response, accessDeniedException) -> { - if (!response.isCommitted()) { - if ("XMLHttpRequest".equals(request.getHeader(AuthenticationConstants.X_REQUESTED_WITH))) { - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - } else if (!response.isCommitted()) { - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - RequestDispatcher dispatcher = request.getRequestDispatcher("/session-expired"); - dispatcher.forward(request, response); - } - } - }) - .defaultAuthenticationEntryPointFor((request, response, ex) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED), new RequestHeaderRequestMatcher(AuthenticationConstants.X_REQUESTED_WITH, "XMLHttpRequest")) - .and() - .headers().cacheControl().disable() - .and() - .csrf(); - - Pattern pattern = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); - Predicate csrfWhitelistPredicate = r -> r.getRequestURI().startsWith("/api/webhook/") - || r.getRequestURI().startsWith("/api/payment/webhook/") - || pattern.matcher(r.getMethod()).matches(); - csrfWhitelistPredicate = csrfWhitelistPredicate.or(r -> r.getRequestURI().equals("/report-csp-violation")); - configurer.requireCsrfProtectionMatcher(new NegatedRequestMatcher(csrfWhitelistPredicate::test)); - - String[] ownershipRequired = new String[]{ - ADMIN_API + "/overridable-template", - ADMIN_API + "/additional-services", - ADMIN_API + "/events/*/additional-field", - ADMIN_API + "/event/*/additional-services/", - ADMIN_API + "/overridable-template/", - ADMIN_API + "/events/*/promo-code", - ADMIN_API + "/reservation/event/*/reservations/list", - ADMIN_API + "/event/*/email/", - ADMIN_API + "/event/*/waiting-queue/load", - ADMIN_API + "/events/*/pending-payments", - ADMIN_API + "/events/*/export", - ADMIN_API + "/events/*/sponsor-scan/export", - ADMIN_API + "/events/*/invoices/**", - ADMIN_API + "/reservation/*/*/*/audit", - ADMIN_API + "/subscription/*/email/", - ADMIN_API + "/organization/*/subscription/**", - ADMIN_API + "/reservation/subscription/**" - }; + CsrfConfigurer configurer = csrfConfigurer(http); + var authenticationManager = createAuthenticationManager(); configurer.csrfTokenRepository(csrfTokenRepository) .and() .headers().frameOptions().disable() // https://github.com/alfio-event/alf.io/issues/1031 X-Frame-Options has been moved to IndexController .and() - .authorizeRequests() - .antMatchers(HttpMethod.GET, ADMIN_API + "/users/current").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers(HttpMethod.POST, ADMIN_API + "/users/check", ADMIN_API + "/users/current/edit", ADMIN_API + "/users/current/update-password").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers(ADMIN_API + "/configuration/**", ADMIN_API + "/users/**").hasAnyRole(ADMIN, OWNER) - .antMatchers(ADMIN_API + "/organizations/new").hasRole(ADMIN) - .antMatchers(ADMIN_API + "/check-in/**").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers(HttpMethod.GET, ownershipRequired).hasAnyRole(ADMIN, OWNER) - .antMatchers(HttpMethod.GET, ADMIN_API + "/**").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers(HttpMethod.POST, ADMIN_API + "/reservation/event/*/new", ADMIN_API + "/reservation/event/*/*").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers(HttpMethod.PUT, ADMIN_API + "/reservation/event/*/*/notify", ADMIN_API + "/reservation/event/*/*/confirm").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers(ADMIN_API + "/**").hasAnyRole(ADMIN, OWNER) - .antMatchers("/admin/**/export/**").hasAnyRole(ADMIN, OWNER) - .antMatchers("/admin/**").hasAnyRole(ADMIN, OWNER, SUPERVISOR) - .antMatchers("/api/attendees/**").denyAll() - .antMatchers("/callback").permitAll() - .antMatchers("/**").permitAll() - .and() + .authorizeRequests(AbstractFormBasedWebSecurity::authorizeRequests) + .authenticationManager(authenticationManager) .formLogin() .loginPage("/authentication") - .loginProcessingUrl("/authenticate") + .loginProcessingUrl(AUTHENTICATE) + .defaultSuccessUrl("/admin") .failureUrl("/authentication?failed") - .and().logout().permitAll(); + .and().logout().permitAll() + .and() + // this allows us to sync between spring session and spring security, thus saving the principal name in the session table + .sessionManagement().maximumSessions(-1).sessionRegistry(sessionRegistry); - http.addFilterBefore(openIdPublicCallbackLoginFilter(publicOpenIdAuthenticationManager), UsernamePasswordAuthenticationFilter.class) + http.addFilterBefore(openIdPublicCallbackLoginFilter(publicOpenIdAuthenticationManager, authenticationManager), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(openIdPublicAuthenticationFilter(publicOpenIdAuthenticationManager), AnonymousAuthenticationFilter.class); // - http.addFilterBefore(new RecaptchaLoginFilter(recaptchaService, "/authenticate", "/authentication?recaptchaFailed", configurationManager), UsernamePasswordAuthenticationFilter.class); + http.addFilterBefore(new RecaptchaLoginFilter(recaptchaService, AUTHENTICATE, "/authentication?recaptchaFailed", configurationManager), UsernamePasswordAuthenticationFilter.class); // call implementation-specific logic - addAdditionalFilters(http); + addAdditionalFilters(http, authenticationManager); + + http.addFilterBefore(csrfFilter(), RecaptchaLoginFilter.class); + + if (environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_DEMO))) { + http.addFilterAfter(new UserCreatorBeforeLoginFilter(userManager, AUTHENTICATE), RecaptchaLoginFilter.class); + } + + return http.build(); + } + + private JdbcUserDetailsManager createUserDetailsManager() { + var userDetailsManager = new JdbcUserDetailsManager(dataSource); + userDetailsManager.setUsersByUsernameQuery("select username, password, enabled from ba_user where username = ?"); + userDetailsManager.setAuthoritiesByUsernameQuery("select username, role from authority where username = ?"); + return userDetailsManager; + } + + private AuthenticationManager createAuthenticationManager() { + var userDetailsManager = createUserDetailsManager(); + var daoAuthenticationProvider = new DaoAuthenticationProvider(); + daoAuthenticationProvider.setPasswordEncoder(passwordEncoder); + daoAuthenticationProvider.setUserDetailsService(userDetailsManager); + return new ProviderManager(List.of(daoAuthenticationProvider, new OpenIdAuthenticationProvider())); + } - //FIXME create session and set csrf cookie if we are getting a v2 public api, an admin api call , will switch to pure cookie based - http.addFilterBefore((servletRequest, servletResponse, filterChain) -> { + private Filter csrfFilter() { + return (servletRequest, servletResponse, filterChain) -> { HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletResponse res = (HttpServletResponse) servletResponse; var reqUri = req.getRequestURI(); - if ((reqUri.startsWith("/api/v2/public/") || reqUri.startsWith("/admin/api/") || reqUri.startsWith("/api/v2/admin/")) && "GET".equalsIgnoreCase(req.getMethod())) { + if ((reqUri.startsWith(API_V2_PUBLIC_PATH) || reqUri.startsWith(ADMIN_API) || reqUri.startsWith("/api/v2/admin/") || reqUri.equals(AUTHENTICATION_STATUS)) && "GET".equalsIgnoreCase(req.getMethod())) { CsrfToken csrf = csrfTokenRepository.loadToken(req); if (csrf == null) { csrf = csrfTokenRepository.generateToken(req); } - Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken()); - cookie.setPath("/"); - res.addCookie(cookie); + res.addHeader(XSRF_TOKEN, csrf.getToken()); + if (!reqUri.startsWith(API_V2_PUBLIC_PATH)) { + // FIXME remove this after the new admin is complete + addCookie(res, csrf); + } } filterChain.doFilter(servletRequest, servletResponse); - }, RecaptchaLoginFilter.class); + }; + } - if (environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_DEMO))) { - http.addFilterAfter(new UserCreatorBeforeLoginFilter(userManager, "/authenticate"), RecaptchaLoginFilter.class); + private static void authorizeRequests(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry auth) { + auth.antMatchers(ADMIN_PUBLIC_API + "/**").denyAll() // Admin public API requests must be authenticated using API-Keys + .antMatchers(HttpMethod.GET, ADMIN_API + "/users/current").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers(HttpMethod.POST, ADMIN_API + "/users/check", ADMIN_API + "/users/current/edit", ADMIN_API + "/users/current/update-password").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers(ADMIN_API + "/configuration/**", ADMIN_API + "/users/**").hasAnyRole(ADMIN, OWNER) + .antMatchers(ADMIN_API + "/organizations/new", ADMIN_API + "/system/**").hasRole(ADMIN) + .antMatchers(ADMIN_API + "/check-in/**").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers(HttpMethod.GET, OWNERSHIP_REQUIRED).hasAnyRole(ADMIN, OWNER) + .antMatchers(HttpMethod.GET, ADMIN_API + "/**").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers(HttpMethod.POST, ADMIN_API + "/reservation/event/*/new", ADMIN_API + "/reservation/event/*/*").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers(HttpMethod.PUT, ADMIN_API + "/reservation/event/*/*/notify", ADMIN_API + "/reservation/event/*/*/confirm").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers(ADMIN_API + "/**").hasAnyRole(ADMIN, OWNER) + .antMatchers("/admin/**/export/**").hasAnyRole(ADMIN, OWNER) + .antMatchers("/admin/**").hasAnyRole(ADMIN, OWNER, SUPERVISOR) + .antMatchers("/api/attendees/**").denyAll() + .antMatchers("/callback").permitAll() + .antMatchers("/**").permitAll(); + } + + private static CsrfConfigurer csrfConfigurer(HttpSecurity http) throws Exception { + var configurer = http.exceptionHandling() + .accessDeniedHandler((request, response, accessDeniedException) -> { + if (!response.isCommitted()) { + if ("XMLHttpRequest".equals(request.getHeader(AuthenticationConstants.X_REQUESTED_WITH))) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + } else if (!response.isCommitted()) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + RequestDispatcher dispatcher = request.getRequestDispatcher("/session-expired"); + dispatcher.forward(request, response); + } + } + }) + .defaultAuthenticationEntryPointFor((request, response, ex) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED), new RequestHeaderRequestMatcher(AuthenticationConstants.X_REQUESTED_WITH, "XMLHttpRequest")) + .and() + .headers().cacheControl().disable() + .and() + .csrf(); + Pattern methodsPattern = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); + Predicate csrfAllowListPredicate = r -> r.getRequestURI().startsWith("/api/webhook/") + || r.getRequestURI().startsWith("/api/payment/webhook/") + || methodsPattern.matcher(r.getMethod()).matches(); + csrfAllowListPredicate = csrfAllowListPredicate.or(r -> r.getRequestURI().equals("/report-csp-violation")); + configurer.requireCsrfProtectionMatcher(new NegatedRequestMatcher(csrfAllowListPredicate::test)); + return configurer; + } + + private void addCookie(HttpServletResponse res, CsrfToken csrf) { + Cookie cookie = new Cookie(XSRF_TOKEN, csrf.getToken()); + cookie.setPath("/"); + boolean prod = environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_LIVE)); + cookie.setSecure(prod); + if (prod) { + cookie.setComment(HttpCookie.SAME_SITE_STRICT_COMMENT); } + res.addCookie(cookie); } /** * This method is called right after applying the {@link RecaptchaLoginFilter} * * @param http + * @param jdbcAuthenticationManager */ - protected void addAdditionalFilters(HttpSecurity http) throws Exception { + protected void addAdditionalFilters(HttpSecurity http, AuthenticationManager jdbcAuthenticationManager) { } private OpenIdAuthenticationFilter openIdPublicAuthenticationFilter(OpenIdAuthenticationManager openIdAuthenticationManager) { return new OpenIdAuthenticationFilter("/openid/authentication", openIdAuthenticationManager, "/", true); } - private OpenIdCallbackLoginFilter openIdPublicCallbackLoginFilter(OpenIdAuthenticationManager openIdAuthenticationManager) throws Exception { + private OpenIdCallbackLoginFilter openIdPublicCallbackLoginFilter(OpenIdAuthenticationManager openIdAuthenticationManager, + AuthenticationManager jdbcAuthenticationManager) { var filter = new OpenIdCallbackLoginFilter(openIdAuthenticationManager, new AntPathRequestMatcher("/openid/callback", "GET"), - authenticationManager()); + jdbcAuthenticationManager); filter.setAuthenticationSuccessHandler((request, response, authentication) -> { var session = request.getSession(); var reservationId = (String) session.getAttribute(RESERVATION_KEY); diff --git a/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java b/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java index b9372dd76b..95087317e4 100644 --- a/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java +++ b/src/main/java/alfio/config/authentication/FormBasedWebSecurity.java @@ -26,6 +26,7 @@ import org.springframework.core.env.Environment; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; import javax.sql.DataSource; @@ -43,7 +44,8 @@ public FormBasedWebSecurity(Environment environment, CsrfTokenRepository csrfTokenRepository, DataSource dataSource, PasswordEncoder passwordEncoder, - PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager) { + PublicOpenIdAuthenticationManager publicOpenIdAuthenticationManager, + SpringSessionBackedSessionRegistry sessionRegistry) { super(environment, userManager, recaptchaService, @@ -51,6 +53,7 @@ public FormBasedWebSecurity(Environment environment, csrfTokenRepository, dataSource, passwordEncoder, - publicOpenIdAuthenticationManager); + publicOpenIdAuthenticationManager, + sessionRegistry); } } diff --git a/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java b/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java index 7fd52cd1f0..b2bffe46de 100644 --- a/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java +++ b/src/main/java/alfio/config/authentication/OpenIdAdminWebSecurity.java @@ -23,25 +23,29 @@ import alfio.manager.openid.PublicOpenIdAuthenticationManager; import alfio.manager.system.ConfigurationManager; import alfio.manager.user.UserManager; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; import javax.sql.DataSource; @Profile("openid") @Configuration(proxyBeanMethods = false) @Order(1) -@Log4j2 public class OpenIdAdminWebSecurity extends AbstractFormBasedWebSecurity { + private static final Logger log = LoggerFactory.getLogger(OpenIdAdminWebSecurity.class); + private final AdminOpenIdAuthenticationManager adminOpenIdAuthenticationManager; public OpenIdAdminWebSecurity(Environment environment, @@ -52,7 +56,8 @@ public OpenIdAdminWebSecurity(Environment environment, DataSource dataSource, PasswordEncoder passwordEncoder, AdminOpenIdAuthenticationManager adminOpenIdAuthenticationManager, - PublicOpenIdAuthenticationManager openIdAuthenticationManager) { + PublicOpenIdAuthenticationManager openIdAuthenticationManager, + SpringSessionBackedSessionRegistry sessionRegistry) { super(environment, userManager, recaptchaService, @@ -60,15 +65,16 @@ public OpenIdAdminWebSecurity(Environment environment, csrfTokenRepository, dataSource, passwordEncoder, - openIdAuthenticationManager); + openIdAuthenticationManager, + sessionRegistry); this.adminOpenIdAuthenticationManager = adminOpenIdAuthenticationManager; } @Override - protected void addAdditionalFilters(HttpSecurity http) throws Exception { + protected void addAdditionalFilters(HttpSecurity http, AuthenticationManager jdbcAuthenticationManager) { var callbackLoginFilter = new OpenIdCallbackLoginFilter(adminOpenIdAuthenticationManager, new AntPathRequestMatcher("/callback", "GET"), - authenticationManager()); + jdbcAuthenticationManager); http.addFilterBefore(callbackLoginFilter, UsernamePasswordAuthenticationFilter.class); log.trace("adding openid filter"); http.addFilterAfter(new OpenIdAuthenticationFilter("/authentication", adminOpenIdAuthenticationManager, "/", false), OpenIdCallbackLoginFilter.class); diff --git a/src/main/java/alfio/config/authentication/support/APIKeyAuthFilter.java b/src/main/java/alfio/config/authentication/support/APIKeyAuthFilter.java index 80561ab300..df39504f67 100644 --- a/src/main/java/alfio/config/authentication/support/APIKeyAuthFilter.java +++ b/src/main/java/alfio/config/authentication/support/APIKeyAuthFilter.java @@ -27,7 +27,10 @@ public class APIKeyAuthFilter extends AbstractPreAuthenticatedProcessingFilter { @Override protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { - return isTokenAuthentication(request) ? StringUtils.trim(request.getHeader("Authorization").substring("apikey ".length())) : null; + if(!isTokenAuthentication(request) || StringUtils.isBlank(request.getHeader("Authorization"))) { + return null; + } + return StringUtils.trim(request.getHeader("Authorization").substring("apikey ".length())); } @Override diff --git a/src/main/java/alfio/config/authentication/support/AuthenticationConstants.java b/src/main/java/alfio/config/authentication/support/AuthenticationConstants.java new file mode 100644 index 0000000000..3cf3fa40e8 --- /dev/null +++ b/src/main/java/alfio/config/authentication/support/AuthenticationConstants.java @@ -0,0 +1,35 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.config.authentication.support; + +public final class AuthenticationConstants { + + private AuthenticationConstants() { + } + + public static final String OPERATOR = "OPERATOR"; + public static final String SPONSOR = "SPONSOR"; + public static final String ADMIN_API = "/admin/api"; + public static final String ADMIN_PUBLIC_API = "/api/v1/admin"; + public static final String SUPERVISOR = "SUPERVISOR"; + public static final String ADMIN = "ADMIN"; + public static final String OWNER = "OWNER"; + public static final String API_CLIENT = "API_CLIENT"; + public static final String SYSTEM_API_CLIENT = "SYSTEM_API_CLIENT"; + public static final String X_REQUESTED_WITH = "X-Requested-With"; + public static final String AUTHENTICATION_STATUS = "/authentication-status"; +} diff --git a/src/main/java/alfio/config/authentication/support/OpenIdAlfioUser.java b/src/main/java/alfio/config/authentication/support/OpenIdAlfioUser.java index 68391d7062..a4b8dd250b 100644 --- a/src/main/java/alfio/config/authentication/support/OpenIdAlfioUser.java +++ b/src/main/java/alfio/config/authentication/support/OpenIdAlfioUser.java @@ -18,14 +18,12 @@ import alfio.model.user.Role; import alfio.model.user.User; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Map; import java.util.Set; @Getter -@AllArgsConstructor public class OpenIdAlfioUser { private final String idToken; private final String subject; @@ -34,6 +32,20 @@ public class OpenIdAlfioUser { private final Set alfioRoles; private final Map> alfioOrganizationAuthorizations; + public OpenIdAlfioUser(String idToken, + String subject, + String email, + User.Type userType, + Set alfioRoles, + Map> alfioOrganizationAuthorizations) { + this.idToken = idToken; + this.subject = subject; + this.email = email; + this.userType = userType; + this.alfioRoles = alfioRoles; + this.alfioOrganizationAuthorizations = alfioOrganizationAuthorizations; + } + public boolean isAdmin() { return userType == User.Type.INTERNAL && alfioRoles.contains(Role.ADMIN); } diff --git a/src/main/java/alfio/config/authentication/support/OpenIdAuthenticationFilter.java b/src/main/java/alfio/config/authentication/support/OpenIdAuthenticationFilter.java index 5423dab443..baa4921cd5 100644 --- a/src/main/java/alfio/config/authentication/support/OpenIdAuthenticationFilter.java +++ b/src/main/java/alfio/config/authentication/support/OpenIdAuthenticationFilter.java @@ -17,7 +17,8 @@ package alfio.config.authentication.support; import alfio.manager.openid.OpenIdAuthenticationManager; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -32,8 +33,10 @@ import java.io.IOException; import java.util.UUID; -@Log4j2 public class OpenIdAuthenticationFilter extends GenericFilterBean { + + private static final Logger log = LoggerFactory.getLogger(OpenIdAuthenticationFilter.class); + public static final String RESERVATION_KEY = "RESERVATION"; public static final String CONTEXT_TYPE_KEY = "CONTEXT_TYPE"; public static final String CONTEXT_ID_KEY = "CONTEXT_ID"; diff --git a/src/main/java/alfio/config/authentication/support/OpenIdCallbackLoginFilter.java b/src/main/java/alfio/config/authentication/support/OpenIdCallbackLoginFilter.java index ebb44b4547..9509218401 100644 --- a/src/main/java/alfio/config/authentication/support/OpenIdCallbackLoginFilter.java +++ b/src/main/java/alfio/config/authentication/support/OpenIdCallbackLoginFilter.java @@ -17,7 +17,8 @@ package alfio.config.authentication.support; import alfio.manager.openid.OpenIdAuthenticationManager; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -34,9 +35,10 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; -@Log4j2 public class OpenIdCallbackLoginFilter extends AbstractAuthenticationProcessingFilter { + private static final Logger log = LoggerFactory.getLogger(OpenIdCallbackLoginFilter.class); + private final RequestMatcher requestMatcher; private final OpenIdAuthenticationManager openIdAuthenticationManager; diff --git a/src/main/java/alfio/config/authentication/support/RequestTypeMatchers.java b/src/main/java/alfio/config/authentication/support/RequestTypeMatchers.java index 720c4f6321..938784dd40 100644 --- a/src/main/java/alfio/config/authentication/support/RequestTypeMatchers.java +++ b/src/main/java/alfio/config/authentication/support/RequestTypeMatchers.java @@ -16,15 +16,17 @@ */ package alfio.config.authentication.support; -import lombok.experimental.UtilityClass; - import javax.servlet.http.HttpServletRequest; import java.util.Locale; -@UtilityClass -public class RequestTypeMatchers { +public final class RequestTypeMatchers { + + private RequestTypeMatchers() { + } + public static boolean isTokenAuthentication(HttpServletRequest request) { String authorization = request.getHeader("Authorization"); - return authorization != null && authorization.toLowerCase(Locale.ENGLISH).startsWith("apikey "); + return (authorization != null && authorization.toLowerCase(Locale.ENGLISH).startsWith("apikey ")) + || request.getRequestURI().startsWith(AuthenticationConstants.ADMIN_PUBLIC_API); } } diff --git a/src/main/java/alfio/config/authentication/support/UserCreatorBeforeLoginFilter.java b/src/main/java/alfio/config/authentication/support/UserCreatorBeforeLoginFilter.java index fefe96d6c7..a7c2ddc642 100644 --- a/src/main/java/alfio/config/authentication/support/UserCreatorBeforeLoginFilter.java +++ b/src/main/java/alfio/config/authentication/support/UserCreatorBeforeLoginFilter.java @@ -30,8 +30,9 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; +import java.util.UUID; -// generate a user if it does not exists, to be used by the demo profile +// generate a user if it does not exist, to be used by the demo profile public class UserCreatorBeforeLoginFilter extends GenericFilterBean { private final UserManager userManager; @@ -51,9 +52,9 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha if (requestMatcher.matches(req) && req.getParameter("username") != null && req.getParameter("password") != null) { String username = req.getParameter("username"); if (!userManager.usernameExists(username)) { - var organizationModification = new OrganizationModification(null, "Demo organization", username, username, null, null); - int orgId = userManager.createOrganization(organizationModification); - userManager.insertUser(orgId, username, "", "", username, Role.OWNER, User.Type.DEMO, req.getParameter("password"), null, null); + var organizationModification = new OrganizationModification(null, UUID.randomUUID().toString(), username, username, null, null); + int orgId = userManager.createOrganization(organizationModification, null); + userManager.insertUser(orgId, username, "", "", username, Role.OWNER, User.Type.DEMO, req.getParameter("password"), null, null, null); } } diff --git a/src/main/java/alfio/config/support/ArrayColumnMapper.java b/src/main/java/alfio/config/support/ArrayColumnMapper.java index 9983e8707f..a4795a3002 100644 --- a/src/main/java/alfio/config/support/ArrayColumnMapper.java +++ b/src/main/java/alfio/config/support/ArrayColumnMapper.java @@ -20,7 +20,6 @@ import ch.digitalfondue.npjt.mapper.ColumnMapper; import ch.digitalfondue.npjt.mapper.ColumnMapperFactory; import ch.digitalfondue.npjt.mapper.ParameterConverter; -import lombok.SneakyThrows; import org.springframework.jdbc.core.RowMapper; import java.lang.annotation.Annotation; @@ -90,7 +89,6 @@ public boolean accept(Class parameterType, Annotation[] annotations) { return hasAnnotation(annotations) && List.class.isAssignableFrom(parameterType); } - @SneakyThrows @Override public void processParameter(ProcessParameterContext processParameterContext) { var arg = processParameterContext.getArg(); @@ -99,8 +97,12 @@ public void processParameter(ProcessParameterContext processParameterContext) { ps.addValue(processParameterContext.getParameterName(), null, Types.ARRAY); } else { Array def = (Array) Arrays.stream(processParameterContext.getParameterAnnotations()).filter(ArrayColumnMapper::annotationFinder).findFirst().orElseThrow(); - var array = processParameterContext.getConnection().createArrayOf(def.type(), ((List) arg).toArray()); - ps.addValue(processParameterContext.getParameterName(), array); + try { + var array = processParameterContext.getConnection().createArrayOf(def.type(), ((List) arg).toArray()); + ps.addValue(processParameterContext.getParameterName(), array); + } catch (SQLException e) { + throw new IllegalStateException(e); + } } } diff --git a/src/main/java/alfio/config/support/EnumTypeColumnMapper.java b/src/main/java/alfio/config/support/EnumTypeColumnMapper.java index 737cef9dee..09e45b8ca0 100644 --- a/src/main/java/alfio/config/support/EnumTypeColumnMapper.java +++ b/src/main/java/alfio/config/support/EnumTypeColumnMapper.java @@ -20,7 +20,6 @@ import ch.digitalfondue.npjt.mapper.ColumnMapper; import ch.digitalfondue.npjt.mapper.ColumnMapperFactory; import ch.digitalfondue.npjt.mapper.ParameterConverter; -import lombok.extern.log4j.Log4j2; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; @@ -31,7 +30,6 @@ import java.util.Arrays; import java.util.Objects; -@Log4j2 public class EnumTypeColumnMapper extends ColumnMapper { private static final int ORDER = Integer.MAX_VALUE - 32; diff --git a/src/main/java/alfio/controller/AdminConfigurationController.java b/src/main/java/alfio/controller/AdminConfigurationController.java index b4750223ca..930fdd398a 100644 --- a/src/main/java/alfio/controller/AdminConfigurationController.java +++ b/src/main/java/alfio/controller/AdminConfigurationController.java @@ -21,9 +21,9 @@ import alfio.manager.payment.StripeConnectManager; import alfio.manager.user.UserManager; import alfio.util.oauth2.AccessTokenResponseDetails; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -41,10 +41,10 @@ import static alfio.manager.payment.StripeConnectManager.STRIPE_CONNECT_REDIRECT_PATH; @Controller -@AllArgsConstructor -@Log4j2 public class AdminConfigurationController { + private static final Logger log = LoggerFactory.getLogger(AdminConfigurationController.class); + private static final String CONNECT_ORG = ".connect.org"; private static final String CONNECT_STATE_PREFIX = ".connect.state."; private static final String REDIRECT_ADMIN = "redirect:/admin/"; @@ -54,6 +54,14 @@ public class AdminConfigurationController { private final MollieConnectManager mollieConnectManager; private final UserManager userManager; + public AdminConfigurationController(StripeConnectManager stripeConnectManager, + MollieConnectManager mollieConnectManager, + UserManager userManager) { + this.stripeConnectManager = stripeConnectManager; + this.mollieConnectManager = mollieConnectManager; + this.userManager = userManager; + } + @GetMapping("/admin/configuration/payment/{provider}/connect/{orgId}") public String oAuthRedirectToAuthorizationURL(Principal principal, @PathVariable("orgId") Integer orgId, @@ -61,9 +69,9 @@ public String oAuthRedirectToAuthorizationURL(Principal principal, HttpSession session) { if(CONNECT_PROVIDERS.contains(provider) && userManager.isOwnerOfOrganization(userManager.findUserByUsername(principal.getName()), orgId)) { var connectURL = getConnector(provider).getConnectURL(orgId); - session.setAttribute(provider+CONNECT_STATE_PREFIX +orgId, connectURL.getState()); + session.setAttribute(provider+CONNECT_STATE_PREFIX +orgId, connectURL.state()); session.setAttribute(provider+CONNECT_ORG, orgId); - return "redirect:" + connectURL.getAuthorizationUrl(); + return "redirect:" + connectURL.authorizationUrl(); } return REDIRECT_ADMIN; } @@ -92,7 +100,7 @@ public String authorize(Principal principal, boolean stateVerified = Objects.equals(persistedState, state); if(stateVerified && code != null) { AccessTokenResponseDetails connectResult = getConnector(provider).storeConnectedAccountId(code, orgId); - if(connectResult.isSuccess()) { + if(connectResult.success()) { return "redirect:/admin/#/configuration/organization/"+orgId; } } else if(stateVerified && StringUtils.isNotEmpty(errorCode)) { diff --git a/src/main/java/alfio/controller/AdminIndexController.java b/src/main/java/alfio/controller/AdminIndexController.java new file mode 100644 index 0000000000..cc7b1a4e5e --- /dev/null +++ b/src/main/java/alfio/controller/AdminIndexController.java @@ -0,0 +1,95 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller; + +import alfio.config.authentication.support.OpenIdAlfioAuthentication; +import alfio.controller.support.CSPConfigurer; +import alfio.manager.system.ConfigurationManager; +import alfio.model.user.Role; +import alfio.util.TemplateManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ClassPathResource; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.Collection; + +import static alfio.controller.Constants.*; +import static alfio.controller.Constants.NONCE; +import static alfio.model.system.ConfigurationKeys.SHOW_PROJECT_BANNER; + +@Controller +public class AdminIndexController { + + private final ConfigurationManager configurationManager; + private final Environment environment; + private final CSPConfigurer cspConfigurer; + private final TemplateManager templateManager; + + public AdminIndexController(ConfigurationManager configurationManager, + Environment environment, + CSPConfigurer cspConfigurer, + TemplateManager templateManager) { + this.configurationManager = configurationManager; + this.environment = environment; + this.cspConfigurer = cspConfigurer; + this.templateManager = templateManager; + } + + @GetMapping("/admin") + public void adminHome(Model model, @Value("${alfio.version}") String version, HttpServletRequest request, HttpServletResponse response, Principal principal) throws IOException { + model.addAttribute("alfioVersion", version); + model.addAttribute("username", principal.getName()); + model.addAttribute("basicConfigurationNeeded", configurationManager.isBasicConfigurationNeeded()); + + boolean isDBAuthentication = !(principal instanceof OpenIdAlfioAuthentication); + model.addAttribute("isDBAuthentication", isDBAuthentication); + if (!isDBAuthentication) { + String idpLogoutRedirectionUrl = ((OpenIdAlfioAuthentication) SecurityContextHolder.getContext().getAuthentication()).getIdpLogoutRedirectionUrl(); + model.addAttribute("idpLogoutRedirectionUrl", idpLogoutRedirectionUrl); + } else { + model.addAttribute("idpLogoutRedirectionUrl", null); + } + + Collection authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities() + .stream().map(GrantedAuthority::getAuthority).toList(); + + boolean isAdmin = authorities.contains(Role.ADMIN.getRoleName()); + model.addAttribute("isOwner", isAdmin || authorities.contains(Role.OWNER.getRoleName())); + model.addAttribute("isAdmin", isAdmin); + // + addCommonModelAttributes(model, request, version, environment); + model.addAttribute("displayProjectBanner", isAdmin && configurationManager.getForSystem(SHOW_PROJECT_BANNER).getValueAsBooleanOrDefault()); + // + + try (var os = response.getOutputStream()) { + response.setContentType(TEXT_HTML_CHARSET_UTF_8); + response.setCharacterEncoding(UTF_8); + var nonce = cspConfigurer.addCspHeader(response, false); + model.addAttribute(NONCE, nonce); + templateManager.renderHtml(new ClassPathResource("alfio/web-templates/admin-index.ms"), model.asMap(), os); + } + } +} diff --git a/src/main/java/alfio/controller/AuthenticationController.java b/src/main/java/alfio/controller/AuthenticationController.java new file mode 100644 index 0000000000..b1db2f4d40 --- /dev/null +++ b/src/main/java/alfio/controller/AuthenticationController.java @@ -0,0 +1,125 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller; + +import alfio.config.authentication.support.AuthenticationConstants; +import alfio.controller.support.CSPConfigurer; +import alfio.controller.support.UserStatus; +import alfio.manager.system.ConfigurationLevel; +import alfio.manager.system.ConfigurationManager; +import alfio.util.TemplateManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.EnumSet; + +import static alfio.controller.Constants.*; +import static alfio.model.system.ConfigurationKeys.ENABLE_CAPTCHA_FOR_LOGIN; +import static alfio.model.system.ConfigurationKeys.RECAPTCHA_API_KEY; +import static com.github.scribejava.core.model.OAuthConstants.NONCE; + +@Controller +public class AuthenticationController { + + private static final String REDIRECT_ADMIN = "redirect:/admin/"; + + private final ConfigurationManager configurationManager; + private final Environment environment; + private final CSPConfigurer cspConfigurer; + private final TemplateManager templateManager; + + public AuthenticationController(ConfigurationManager configurationManager, + Environment environment, + CSPConfigurer cspConfigurer, + TemplateManager templateManager) { + this.configurationManager = configurationManager; + this.environment = environment; + this.cspConfigurer = cspConfigurer; + this.templateManager = templateManager; + } + + @GetMapping(AuthenticationConstants.AUTHENTICATION_STATUS) + public ResponseEntity authenticationStatus(Principal principal, + @Value("${alfio.version}") String version) { + + return ResponseEntity.ok(new UserStatus( + principal != null, + principal != null ? principal.getName() : null, + version, + demoModeEnabled(environment), + devModeEnabled(environment), + prodModeEnabled(environment) + )); + } + + @GetMapping("/authentication") + public void getLoginPage(@RequestParam(value="failed", required = false) String failed, + @RequestParam(value = "recaptchaFailed", required = false) String recaptchaFailed, + Model model, + Principal principal, + HttpServletRequest request, + HttpServletResponse response, + @Value("${alfio.version}") String version) throws IOException { + + if(principal != null) { + response.sendRedirect("/admin/"); + return; + } + model.addAttribute("failed", failed != null); + model.addAttribute("recaptchaFailed", recaptchaFailed != null); + model.addAttribute("hasRecaptchaApiKey", false); + + // + addCommonModelAttributes(model, request, version, environment); + model.addAttribute("request", request); + + // + + var configuration = configurationManager.getFor(EnumSet.of(RECAPTCHA_API_KEY, ENABLE_CAPTCHA_FOR_LOGIN), ConfigurationLevel.system()); + + configuration.get(RECAPTCHA_API_KEY).getValue() + .filter(key -> configuration.get(ENABLE_CAPTCHA_FOR_LOGIN).getValueAsBooleanOrDefault()) + .ifPresent(key -> { + model.addAttribute("hasRecaptchaApiKey", true); + model.addAttribute("recaptchaApiKey", key); + }); + try (var os = response.getOutputStream()) { + response.setContentType(TEXT_HTML_CHARSET_UTF_8); + response.setCharacterEncoding(UTF_8); + var nonce = cspConfigurer.addCspHeader(response, false); + model.addAttribute(NONCE, nonce); + templateManager.renderHtml(new ClassPathResource("alfio/web-templates/login.ms"), model.asMap(), os); + } + } + + @PostMapping("/authenticate") + public String doLogin() { + return REDIRECT_ADMIN; + } + +} diff --git a/src/main/java/alfio/controller/Constants.java b/src/main/java/alfio/controller/Constants.java new file mode 100644 index 0000000000..b41f6487f6 --- /dev/null +++ b/src/main/java/alfio/controller/Constants.java @@ -0,0 +1,64 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller; + +import alfio.config.Initializer; +import alfio.config.WebSecurityConfig; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.ui.Model; + +import javax.servlet.http.HttpServletRequest; + +public interface Constants { + String TEXT_HTML_CHARSET_UTF_8 = "text/html;charset=UTF-8"; + String UTF_8 = "UTF-8"; + String NONCE = "nonce"; + String REDIRECT = "redirect:"; + String EVENT_SHORT_NAME = "eventShortName"; + String NOT_FOUND = "not-found"; + String CONTENT = "content"; + String PROPERTY = "property"; + + static void addCommonModelAttributes(Model model, HttpServletRequest request, String version, Environment environment) { + var contextPath = StringUtils.appendIfMissing(request.getContextPath(), "/") + version; + model.addAttribute("contextPath", contextPath); + model.addAttribute("demoModeEnabled", demoModeEnabled(environment)); + model.addAttribute("devModeEnabled", devModeEnabled(environment)); + model.addAttribute("prodModeEnabled", prodModeEnabled(environment)); + model.addAttribute(WebSecurityConfig.CSRF_PARAM_NAME, request.getAttribute(CsrfToken.class.getName())); + } + + static boolean prodModeEnabled(Environment environment) { + return profileActive(environment, Initializer.PROFILE_LIVE); + } + + static boolean devModeEnabled(Environment environment) { + return profileActive(environment, Initializer.PROFILE_DEV); + } + + static boolean demoModeEnabled(Environment environment) { + return profileActive(environment, Initializer.PROFILE_DEMO); + } + + private static boolean profileActive(Environment environment, String profile) { + return environment.acceptsProfiles(Profiles.of(profile)); + } + +} diff --git a/src/main/java/alfio/controller/IndexController.java b/src/main/java/alfio/controller/IndexController.java index 0d90c44da3..2b6ee9e674 100644 --- a/src/main/java/alfio/controller/IndexController.java +++ b/src/main/java/alfio/controller/IndexController.java @@ -16,40 +16,32 @@ */ package alfio.controller; -import alfio.config.Initializer; -import alfio.config.WebSecurityConfig; -import alfio.config.authentication.support.OpenIdAlfioAuthentication; +import alfio.controller.api.v2.model.Language; import alfio.controller.api.v2.user.support.EventLoader; +import alfio.controller.support.CSPConfigurer; import alfio.manager.PurchaseContextManager; import alfio.manager.i18n.MessageSourceManager; import alfio.manager.openid.OpenIdAuthenticationManager; import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; -import alfio.model.*; +import alfio.model.ContentLanguage; +import alfio.model.EventDescription; +import alfio.model.FileBlobMetadata; +import alfio.model.TicketReservationStatusAndValidation; import alfio.model.system.ConfigurationKeys; -import alfio.model.user.Role; import alfio.repository.*; import alfio.repository.user.OrganizationRepository; import alfio.util.Json; import alfio.util.MustacheCustomTag; import alfio.util.RequestUtils; -import alfio.util.TemplateManager; import ch.digitalfondue.jfiveparse.*; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Hex; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; +import org.springframework.context.annotation.Profile; import org.springframework.core.io.ClassPathResource; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.util.UriComponentsBuilder; @@ -61,45 +53,26 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; -import java.security.Principal; -import java.security.SecureRandom; import java.util.*; import java.util.regex.Pattern; -import java.util.stream.Collectors; -import static alfio.model.system.ConfigurationKeys.*; +import static alfio.config.Initializer.PROFILE_LIVE; +import static alfio.controller.Constants.*; +import static alfio.model.system.ConfigurationKeys.BASE_CUSTOM_CSS; +import static alfio.util.HttpUtils.APPLICATION_JSON; +import static java.util.Objects.requireNonNull; @Controller -@AllArgsConstructor -@Slf4j +@Profile(PROFILE_LIVE) public class IndexController { - private static final String REDIRECT_ADMIN = "redirect:/admin/"; private static final String TEXT_HTML_CHARSET_UTF_8 = "text/html;charset=UTF-8"; private static final String UTF_8 = "UTF-8"; - - private static final SecureRandom SECURE_RANDOM = new SecureRandom(); - - private static final Document INDEX_PAGE; - private static final Document OPEN_GRAPH_PAGE; - - static { - try (var idxIs = new ClassPathResource("alfio-public-frontend-index.html").getInputStream(); - var idxOpenIs = new ClassPathResource("alfio/web-templates/event-open-graph-page.html").getInputStream(); - var idxIsR = new InputStreamReader(idxIs, StandardCharsets.UTF_8); - var idxOpenGraphReader = new InputStreamReader(idxOpenIs, StandardCharsets.UTF_8)) { - INDEX_PAGE = JFiveParse.parse(idxIsR); - OPEN_GRAPH_PAGE = JFiveParse.parse(idxOpenGraphReader); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - + private final Document indexPage; + private final Document openGraphPage; private final ConfigurationManager configurationManager; private final EventRepository eventRepository; - private final Environment environment; - private final TemplateManager templateManager; private final FileUploadRepository fileUploadRepository; private final MessageSourceManager messageSourceManager; private final EventDescriptionRepository eventDescriptionRepository; @@ -108,6 +81,46 @@ public class IndexController { private final SubscriptionRepository subscriptionRepository; private final EventLoader eventLoader; private final PurchaseContextManager purchaseContextManager; + private final Json json; + private final CsrfTokenRepository csrfTokenRepository; + private final CSPConfigurer cspConfigurer; + + public IndexController(ConfigurationManager configurationManager, + EventRepository eventRepository, + FileUploadRepository fileUploadRepository, + MessageSourceManager messageSourceManager, + EventDescriptionRepository eventDescriptionRepository, + OrganizationRepository organizationRepository, + TicketReservationRepository ticketReservationRepository, + SubscriptionRepository subscriptionRepository, + EventLoader eventLoader, + PurchaseContextManager purchaseContextManager, + CsrfTokenRepository csrfTokenRepository, + CSPConfigurer cspConfigurer, + Json json) { + this.configurationManager = configurationManager; + this.eventRepository = eventRepository; + this.fileUploadRepository = fileUploadRepository; + this.messageSourceManager = messageSourceManager; + this.eventDescriptionRepository = eventDescriptionRepository; + this.organizationRepository = organizationRepository; + this.ticketReservationRepository = ticketReservationRepository; + this.subscriptionRepository = subscriptionRepository; + this.eventLoader = eventLoader; + this.purchaseContextManager = purchaseContextManager; + this.csrfTokenRepository = csrfTokenRepository; + this.cspConfigurer = cspConfigurer; + this.json = json; + try (var idxIs = new ClassPathResource("alfio-public-frontend-index.html").getInputStream(); + var idxOpenIs = new ClassPathResource("alfio/web-templates/event-open-graph-page.html").getInputStream(); + var idxIsR = new InputStreamReader(idxIs, StandardCharsets.UTF_8); + var idxOpenGraphReader = new InputStreamReader(idxOpenIs, StandardCharsets.UTF_8)) { + indexPage = JFiveParse.parse(idxIsR); + openGraphPage = JFiveParse.parse(idxOpenGraphReader); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } @RequestMapping(value = "/", method = RequestMethod.HEAD) @@ -193,7 +206,7 @@ public ResponseEntity replyToK8s() { "/my-orders", "/my-profile", }) - public void replyToIndex(@PathVariable(value = "eventShortName", required = false) String eventShortName, + public void replyToIndex(@PathVariable(value = EVENT_SHORT_NAME, required = false) String eventShortName, @PathVariable(value = "subscriptionId", required = false) String subscriptionId, @RequestHeader(value = "User-Agent", required = false) String userAgent, @RequestParam(value = "lang", required = false) String lang, @@ -203,50 +216,55 @@ public void replyToIndex(@PathVariable(value = "eventShortName", required = fals response.setContentType(TEXT_HTML_CHARSET_UTF_8); response.setCharacterEncoding(UTF_8); - var nonce = addCspHeader(response, detectConfigurationLevel(eventShortName, subscriptionId), true); + var nonce = cspConfigurer.addCspHeader(response, detectConfigurationLevel(eventShortName, subscriptionId), true); if (eventShortName != null && RequestUtils.isSocialMediaShareUA(userAgent) && eventRepository.existsByShortName(eventShortName)) { try (var os = response.getOutputStream(); var osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) { - var res = getOpenGraphPage((Document) OPEN_GRAPH_PAGE.cloneNode(true), eventShortName, request, lang); + var res = getOpenGraphPage((Document) openGraphPage.cloneNode(true), eventShortName, request, lang); JFiveParse.serialize(res, osw); } } else { try (var os = response.getOutputStream(); var osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) { var baseCustomCss = configurationManager.getForSystem(BASE_CUSTOM_CSS).getValueOrNull(); - var idx = INDEX_PAGE.cloneNode(true); + var idx = indexPage.cloneNode(true); if(session.getAttribute(OpenIdAuthenticationManager.USER_SIGNED_UP) != null) { Optional.ofNullable(IterableUtils.get(idx.getElementsByTagName("html"), 0)) .ifPresent(html -> html.setAttribute("data-signed-up", "true")); session.removeAttribute(OpenIdAuthenticationManager.USER_SIGNED_UP); } - idx.getElementsByTagName("script").forEach(element -> element.setAttribute("nonce", nonce)); + idx.getElementsByTagName("script").forEach(element -> element.setAttribute(NONCE, nonce)); var head = idx.getElementsByTagName("head").get(0); - head.appendChild(buildScripTag(Json.toJson(configurationManager.getInfo(session)), "application/json", "preload-info", null)); - head.appendChild(buildScripTag(Json.toJson(messageSourceManager.getBundleAsMap("alfio.i18n.public", true, "en")), "application/json", "preload-bundle", "en")); + head.appendChild(buildScripTag(json.asJsonString(configurationManager.getInfo(session)), APPLICATION_JSON, "preload-info", null)); + var httpServletRequest = requireNonNull(request.getNativeRequest(HttpServletRequest.class)); + head.appendChild(buildMetaTag("GID", request.getSessionId())); + var csrf = csrfTokenRepository.loadToken(httpServletRequest); + if (csrf == null) { + csrf = csrfTokenRepository.generateToken(httpServletRequest); + } + head.appendChild(buildMetaTag("XSRF_TOKEN", csrf.getToken())); if (baseCustomCss != null) { var style = new Element("style"); style.setAttribute("type", "text/css"); style.appendChild(new Text(baseCustomCss)); head.appendChild(style); } - if (eventShortName != null) { - eventLoader.loadEventInfo(eventShortName, session).ifPresent(ev -> { - head.appendChild(buildScripTag(Json.toJson(ev), "application/json", "preload-event", eventShortName)); - }); - } + preloadTranslations(eventShortName, request, session, eventLoader, head, messageSourceManager, idx, json, lang); JFiveParse.serialize(idx, osw); } } } @GetMapping("/event/{eventShortName}/reservation/{reservationId}") - public String redirectEventToReservation(@PathVariable(value = "eventShortName") String eventShortName, @PathVariable(value = "reservationId") String reservationId) { + public String redirectEventToReservation(@PathVariable(value = EVENT_SHORT_NAME) String eventShortName, + @PathVariable(value = "reservationId") String reservationId, + @RequestParam(value = "subscription", required = false) String subscriptionId) { if (eventRepository.existsByShortName(eventShortName)) { var reservationStatusUrlSegment = ticketReservationRepository.findOptionalStatusAndValidationById(reservationId) - .map(IndexController::reservationStatusToUrlMapping).orElse("not-found"); - - return "redirect:" + UriComponentsBuilder.fromPath("/event/{eventShortName}/reservation/{reservationId}/{status}") - .buildAndExpand(Map.of("eventShortName", eventShortName, "reservationId", reservationId, "status",reservationStatusUrlSegment)) + .map(IndexController::reservationStatusToUrlMapping).orElse(NOT_FOUND); + return REDIRECT + UriComponentsBuilder.fromPath("/event/{eventShortName}/reservation/{reservationId}/{status}") + // if subscription param is present, we forward it to the reservation resource + .queryParamIfPresent("subscription", Optional.ofNullable(StringUtils.trimToNull(subscriptionId))) + .buildAndExpand(Map.of(EVENT_SHORT_NAME, eventShortName, "reservationId", reservationId, "status",reservationStatusUrlSegment)) .toUriString(); } else { return "redirect:/"; @@ -257,9 +275,9 @@ public String redirectEventToReservation(@PathVariable(value = "eventShortName") public String redirectSubscriptionToReservation(@PathVariable("subscriptionId") String subscriptionId, @PathVariable("reservationId") String reservationId) { if (subscriptionRepository.existsById(UUID.fromString(subscriptionId))) { var reservationStatusUrlSegment = ticketReservationRepository.findOptionalStatusAndValidationById(reservationId) - .map(IndexController::reservationStatusToUrlMapping).orElse("not-found"); + .map(IndexController::reservationStatusToUrlMapping).orElse(NOT_FOUND); - return "redirect:" + UriComponentsBuilder.fromPath("/subscription/{subscriptionId}/reservation/{reservationId}/{status}") + return REDIRECT + UriComponentsBuilder.fromPath("/subscription/{subscriptionId}/reservation/{reservationId}/{status}") .buildAndExpand(Map.of("subscriptionId", subscriptionId, "reservationId", reservationId, "status",reservationStatusUrlSegment)) .toUriString(); } else { @@ -267,6 +285,33 @@ public String redirectSubscriptionToReservation(@PathVariable("subscriptionId") } } + static void preloadTranslations(String eventShortName, + ServletWebRequest request, + HttpSession session, + EventLoader eventLoader, + Element head, + MessageSourceManager messageSourceManager, + Node idx, + Json json, + String lang) { + String preloadLang = Objects.requireNonNullElse(lang, "en"); + if (eventShortName != null) { + var eventInfoOptional = eventLoader.loadEventInfo(eventShortName, session); + if (eventInfoOptional.isPresent()) { + var ev = eventInfoOptional.get(); + head.appendChild(buildScripTag(json.asJsonString(ev), APPLICATION_JSON, "preload-event", eventShortName)); + preloadLang = getMatchingLocale(request, ev.getContentLanguages().stream().map(Language::getLocale).toList(), lang).getLanguage(); + } + } + head.appendChild(buildScripTag(json.asJsonString(messageSourceManager.getBundleAsMap("alfio.i18n.public", true, preloadLang, MessageSourceManager.PUBLIC_FRONTEND)), "application/json", "preload-bundle", preloadLang)); + // add fallback in english + if (!"en".equals(preloadLang)) { + head.appendChild(buildScripTag(json.asJsonString(messageSourceManager.getBundleAsMap("alfio.i18n.public", true, "en", MessageSourceManager.PUBLIC_FRONTEND)), "application/json", "preload-bundle", "en")); + } + var htmlElement = IterableUtils.get(idx.getElementsByTagName("html"), 0); + htmlElement.setAttribute("lang", preloadLang); + } + private static Element buildScripTag(String content, String type, String id, String param) { var e = new Element("script"); e.appendChild(new Text(content)); @@ -279,27 +324,39 @@ private static Element buildScripTag(String content, String type, String id, Str } private static String reservationStatusToUrlMapping(TicketReservationStatusAndValidation status) { - switch (status.getStatus()) { - case PENDING: return Boolean.TRUE.equals(status.getValidated()) ? "overview" : "book"; - case COMPLETE: return "success"; - case OFFLINE_PAYMENT: return "waiting-payment"; - case DEFERRED_OFFLINE_PAYMENT: return "deferred-payment"; - case EXTERNAL_PROCESSING_PAYMENT: - case WAITING_EXTERNAL_CONFIRMATION: return "processing-payment"; - case IN_PAYMENT: - case STUCK: return "error"; - default: return "not-found"; // <- this may be a little bit aggressive + return switch (status.getStatus()) { + case PENDING -> Boolean.TRUE.equals(status.getValidated()) ? "overview" : "book"; + case COMPLETE, FINALIZING -> "success"; + case OFFLINE_PAYMENT, OFFLINE_FINALIZING -> "waiting-payment"; + case DEFERRED_OFFLINE_PAYMENT -> "deferred-payment"; + case EXTERNAL_PROCESSING_PAYMENT, WAITING_EXTERNAL_CONFIRMATION -> "processing-payment"; + case IN_PAYMENT, STUCK -> "error"; + default -> NOT_FOUND; // <- this may be a little bit aggressive + }; + } + + + /** + * Return the best matching locale. + * + * @param request + * @param contextLanguages list of languages configured for the event (o other contexts) + * @param lang override passed as parameter + * @return + */ + private static Locale getMatchingLocale(ServletWebRequest request, List contextLanguages, String lang) { + var locale = RequestUtils.getMatchingLocale(request, contextLanguages); + if (lang != null && contextLanguages.stream().anyMatch(lang::equalsIgnoreCase)) { + locale = Locale.forLanguageTag(lang); } + return locale; } // see https://github.com/alfio-event/alf.io/issues/708 // use ngrok to test the preview private Document getOpenGraphPage(Document eventOpenGraph, String eventShortName, ServletWebRequest request, String lang) { var event = eventRepository.findByShortName(eventShortName); - var locale = RequestUtils.getMatchingLocale(request, event); - if (lang != null && event.getContentLanguages().stream().map(ContentLanguage::getLanguage).anyMatch(lang::equalsIgnoreCase)) { - locale = Locale.forLanguageTag(lang); - } + var locale = getMatchingLocale(request, event.getContentLanguages().stream().map(ContentLanguage::getLanguage).toList(), lang); var baseUrl = configurationManager.getForSystem(ConfigurationKeys.BASE_URL).getRequiredValue(); @@ -311,37 +368,45 @@ private Document getOpenGraphPage(Document eventOpenGraph, String eventShortName // - getMetaElement(eventOpenGraph, "name", "twitter:image").setAttribute("content", baseUrl + "/file/" + event.getFileBlobId()); + getMetaElement(eventOpenGraph, "name", "twitter:image").setAttribute(CONTENT, baseUrl + "/file/" + event.getFileBlobId()); // eventOpenGraph.getElementsByTagName("title").get(0).appendChild(new Text(title)); - getMetaElement(eventOpenGraph, "property", "og:title").setAttribute("content", title); - getMetaElement(eventOpenGraph, "property","og:image").setAttribute("content", baseUrl + "/file/" + event.getFileBlobId()); + getMetaElement(eventOpenGraph, PROPERTY, "og:title").setAttribute(CONTENT, title); + getMetaElement(eventOpenGraph, PROPERTY,"og:image").setAttribute(CONTENT, baseUrl + "/file/" + event.getFileBlobId()); var eventDesc = eventDescriptionRepository.findDescriptionByEventIdTypeAndLocale(event.getId(), EventDescription.EventDescriptionType.DESCRIPTION, locale.toLanguageTag()).orElse("").trim(); var firstLine = Pattern.compile("\n").splitAsStream(MustacheCustomTag.renderToTextCommonmark(eventDesc)).findFirst().orElse(""); - getMetaElement(eventOpenGraph, "property","og:description").setAttribute("content", firstLine); + getMetaElement(eventOpenGraph, PROPERTY,"og:description").setAttribute(CONTENT, firstLine); var org = organizationRepository.getById(event.getOrganizationId()); var author = String.format("%s <%s>", org.getName(), org.getEmail()); - getMetaElement(eventOpenGraph, "name", "author").setAttribute("content", author); + getMetaElement(eventOpenGraph, "name", "author").setAttribute(CONTENT, author); fileUploadRepository.findById(event.getFileBlobId()).ifPresent(metadata -> { var attributes = metadata.getAttributes(); if (attributes.containsKey(FileBlobMetadata.ATTR_IMG_HEIGHT) && attributes.containsKey(FileBlobMetadata.ATTR_IMG_WIDTH)) { - head.appendChild(buildMetaTag("og:image:width", attributes.get(FileBlobMetadata.ATTR_IMG_WIDTH))); - head.appendChild(buildMetaTag("og:image:height", attributes.get(FileBlobMetadata.ATTR_IMG_HEIGHT))); + head.appendChild(buildOGMetaTag("og:image:width", attributes.get(FileBlobMetadata.ATTR_IMG_WIDTH))); + head.appendChild(buildOGMetaTag("og:image:height", attributes.get(FileBlobMetadata.ATTR_IMG_HEIGHT))); } }); return eventOpenGraph; } - private static Element buildMetaTag(String propertyValue, String contentValue) { + private static Element buildOGMetaTag(String propertyValue, String contentValue) { + return buildMetaTag(PROPERTY, propertyValue, contentValue); + } + + private static Element buildMetaTag(String name, String content) { + return buildMetaTag("name", name, content); + } + + private static Element buildMetaTag(String property, String propertyValue, String content) { var meta = new Element("meta"); - meta.setAttribute("property", propertyValue); - meta.setAttribute("content", contentValue); + meta.setAttribute(property, propertyValue); + meta.setAttribute(CONTENT, content); return meta; } @@ -352,155 +417,15 @@ private static Element getMetaElement(Document document, String attrName, String @GetMapping(value = { "/event/{eventShortName}/code/{code}", "/e/{eventShortName}/c/{code}"}) - public String redirectCode(@PathVariable("eventShortName") String eventName, + public String redirectCode(@PathVariable(EVENT_SHORT_NAME) String eventName, @PathVariable("code") String code) { - return "redirect:" + UriComponentsBuilder.fromPath("/api/v2/public/event/{eventShortName}/code/{code}") - .build(Map.of("eventShortName", eventName, "code", code)); + return REDIRECT + UriComponentsBuilder.fromPath("/api/v2/public/event/{eventShortName}/code/{code}") + .build(Map.of(EVENT_SHORT_NAME, eventName, "code", code)); } @GetMapping("/e/{eventShortName}") - public String redirectEvent(@PathVariable("eventShortName") String eventName) { - return "redirect:" + UriComponentsBuilder.fromPath("/event/{eventShortName}").build(Map.of("eventShortName", eventName)); - } - - // login related - @GetMapping("/authentication") - public void getLoginPage(@RequestParam(value="failed", required = false) String failed, - @RequestParam(value = "recaptchaFailed", required = false) String recaptchaFailed, - Model model, - Principal principal, - HttpServletRequest request, - HttpServletResponse response, - @Value("${alfio.version}") String version) throws IOException { - - if(principal != null) { - response.sendRedirect("/admin/"); - return; - } - model.addAttribute("failed", failed != null); - model.addAttribute("recaptchaFailed", recaptchaFailed != null); - model.addAttribute("hasRecaptchaApiKey", false); - - // - addCommonModelAttributes(model, request, version); - model.addAttribute("request", request); - - // - - var configuration = configurationManager.getFor(EnumSet.of(RECAPTCHA_API_KEY, ENABLE_CAPTCHA_FOR_LOGIN), ConfigurationLevel.system()); - - configuration.get(RECAPTCHA_API_KEY).getValue() - .filter(key -> configuration.get(ENABLE_CAPTCHA_FOR_LOGIN).getValueAsBooleanOrDefault()) - .ifPresent(key -> { - model.addAttribute("hasRecaptchaApiKey", true); - model.addAttribute("recaptchaApiKey", key); - }); - try (var os = response.getOutputStream()) { - response.setContentType(TEXT_HTML_CHARSET_UTF_8); - response.setCharacterEncoding(UTF_8); - var nonce = addCspHeader(response, false); - model.addAttribute("nonce", nonce); - templateManager.renderHtml(new ClassPathResource("alfio/web-templates/login.ms"), model.asMap(), os); - } - } - - @PostMapping("/authenticate") - public String doLogin() { - return REDIRECT_ADMIN; - } - // - - - // admin index - @GetMapping("/admin") - public void adminHome(Model model, @Value("${alfio.version}") String version, HttpServletRequest request, HttpServletResponse response, Principal principal) throws IOException { - model.addAttribute("alfioVersion", version); - model.addAttribute("username", principal.getName()); - model.addAttribute("basicConfigurationNeeded", configurationManager.isBasicConfigurationNeeded()); - - boolean isDBAuthentication = !(principal instanceof OpenIdAlfioAuthentication); - model.addAttribute("isDBAuthentication", isDBAuthentication); - if (!isDBAuthentication) { - String idpLogoutRedirectionUrl = ((OpenIdAlfioAuthentication) SecurityContextHolder.getContext().getAuthentication()).getIdpLogoutRedirectionUrl(); - model.addAttribute("idpLogoutRedirectionUrl", idpLogoutRedirectionUrl); - } else { - model.addAttribute("idpLogoutRedirectionUrl", null); - } - - Collection authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities() - .stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); - - boolean isAdmin = authorities.contains(Role.ADMIN.getRoleName()); - model.addAttribute("isOwner", isAdmin || authorities.contains(Role.OWNER.getRoleName())); - model.addAttribute("isAdmin", isAdmin); - // - addCommonModelAttributes(model, request, version); - model.addAttribute("displayProjectBanner", isAdmin && configurationManager.getForSystem(SHOW_PROJECT_BANNER).getValueAsBooleanOrDefault()); - // - - try (var os = response.getOutputStream()) { - response.setContentType(TEXT_HTML_CHARSET_UTF_8); - response.setCharacterEncoding(UTF_8); - var nonce = addCspHeader(response, false); - model.addAttribute("nonce", nonce); - templateManager.renderHtml(new ClassPathResource("alfio/web-templates/admin-index.ms"), model.asMap(), os); - } - } - - private void addCommonModelAttributes(Model model, HttpServletRequest request, String version) { - var contextPath = StringUtils.appendIfMissing(request.getContextPath(), "/") + version; - model.addAttribute("contextPath", contextPath); - model.addAttribute("demoModeEnabled", environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_DEMO))); - model.addAttribute("devModeEnabled", environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_DEV))); - model.addAttribute("prodModeEnabled", environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_LIVE))); - model.addAttribute(WebSecurityConfig.CSRF_PARAM_NAME, request.getAttribute(CsrfToken.class.getName())); - } - - - private static String getNonce() { - var nonce = new byte[16]; //128 bit = 16 bytes - SECURE_RANDOM.nextBytes(nonce); - return Hex.encodeHexString(nonce); - } - - public String addCspHeader(HttpServletResponse response, boolean embeddingSupported) { - return addCspHeader(response, ConfigurationLevel.system(), embeddingSupported); - } - - public String addCspHeader(HttpServletResponse response, ConfigurationLevel configurationLevel, boolean embeddingSupported) { - - var nonce = getNonce(); - - String reportUri = ""; - - var conf = configurationManager.getFor(List.of(SECURITY_CSP_REPORT_ENABLED, SECURITY_CSP_REPORT_URI, EMBED_ALLOWED_ORIGINS), configurationLevel); - - boolean enabledReport = conf.get(SECURITY_CSP_REPORT_ENABLED).getValueAsBooleanOrDefault(); - if (enabledReport) { - reportUri = " report-uri " + conf.get(SECURITY_CSP_REPORT_URI).getValueOrDefault("/report-csp-violation"); - } - // - // https://csp.withgoogle.com/docs/strict-csp.html - // with base-uri set to 'self' - - var frameAncestors = "'none'"; - var allowedContainer = conf.get(EMBED_ALLOWED_ORIGINS).getValueOrNull(); - if (embeddingSupported && StringUtils.isNotBlank(allowedContainer)) { - var splitHosts = allowedContainer.split("[,\n]"); - frameAncestors = String.join(" ", splitHosts); - // IE11 - response.addHeader("X-Frame-Options", "ALLOW-FROM "+splitHosts[0]); - } else { - response.addHeader("X-Frame-Options", "DENY"); - } - - response.addHeader("Content-Security-Policy", "object-src 'none'; "+ - "script-src 'strict-dynamic' 'nonce-" + nonce + "' 'unsafe-inline' http: https:; " + - "base-uri 'self'; " + - "frame-ancestors " + frameAncestors + "; " - + reportUri); - - return nonce; + public String redirectEvent(@PathVariable(EVENT_SHORT_NAME) String eventName) { + return REDIRECT + UriComponentsBuilder.fromPath("/event/{eventShortName}").build(Map.of(EVENT_SHORT_NAME, eventName)); } private ConfigurationLevel detectConfigurationLevel(String eventShortName, String subscriptionId) { diff --git a/src/main/java/alfio/controller/OnlineCheckInController.java b/src/main/java/alfio/controller/OnlineCheckInController.java index 8bb9cac92e..93408c2120 100644 --- a/src/main/java/alfio/controller/OnlineCheckInController.java +++ b/src/main/java/alfio/controller/OnlineCheckInController.java @@ -19,9 +19,9 @@ import alfio.manager.CheckInManager; import alfio.manager.ExtensionManager; import alfio.manager.TicketReservationManager; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.digest.DigestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -35,14 +35,20 @@ import static alfio.util.EventUtil.findMatchingLink; @Controller -@AllArgsConstructor -@Log4j2 public class OnlineCheckInController { + private static final Logger log = LoggerFactory.getLogger(OnlineCheckInController.class); + private final TicketReservationManager ticketReservationManager; private final CheckInManager checkInManager; private final ExtensionManager extensionManager; + public OnlineCheckInController(TicketReservationManager ticketReservationManager, CheckInManager checkInManager, ExtensionManager extensionManager) { + this.ticketReservationManager = ticketReservationManager; + this.checkInManager = checkInManager; + this.extensionManager = extensionManager; + } + @GetMapping("/event/{shortName}/ticket/{ticketUUID}/check-in/{ticketCodeHash}") public String performCheckIn(@PathVariable("shortName") String eventShortName, @PathVariable("ticketUUID") String ticketUUID, @@ -52,7 +58,7 @@ public String performCheckIn(@PathVariable("shortName") String eventShortName, .flatMap(data -> { var ticket = data.getTicket(); var event = data.getEventWithCheckInInfo(); - String ticketCode = ticket.ticketCode(event.getPrivateKey()); + String ticketCode = ticket.ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive()); if(MessageDigest.isEqual(DigestUtils.sha256Hex(ticketCode).getBytes(StandardCharsets.UTF_8), ticketCodeHash.getBytes(StandardCharsets.UTF_8))) { log.debug("code successfully validated for ticket {}", ticketUUID); // check-in can be done. Let's check if there is a redirection URL diff --git a/src/main/java/alfio/controller/api/ApiControllerExceptionHandler.java b/src/main/java/alfio/controller/api/ApiControllerExceptionHandler.java index 0ac1cf1933..c51c25e081 100644 --- a/src/main/java/alfio/controller/api/ApiControllerExceptionHandler.java +++ b/src/main/java/alfio/controller/api/ApiControllerExceptionHandler.java @@ -17,7 +17,8 @@ package alfio.controller.api; import alfio.controller.api.v2.user.support.ReservationAccessDenied; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageConversionException; import org.springframework.web.HttpRequestMethodNotSupportedException; @@ -33,9 +34,10 @@ "alfio.controller.api.support", "alfio.controller.api.v1", "alfio.controller.api.v2"}) -@Log4j2 public class ApiControllerExceptionHandler { + private static final Logger log = LoggerFactory.getLogger(ApiControllerExceptionHandler.class); + @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody diff --git a/src/main/java/alfio/controller/api/admin/AdditionalServiceApiController.java b/src/main/java/alfio/controller/api/admin/AdditionalServiceApiController.java index c3759ee407..9db019422c 100644 --- a/src/main/java/alfio/controller/api/admin/AdditionalServiceApiController.java +++ b/src/main/java/alfio/controller/api/admin/AdditionalServiceApiController.java @@ -19,6 +19,7 @@ import alfio.manager.AdditionalServiceManager; import alfio.manager.EventManager; import alfio.model.AdditionalService; +import alfio.model.AdditionalServiceItem; import alfio.model.Event; import alfio.model.PriceContainer; import alfio.model.modification.EventModification; @@ -27,9 +28,9 @@ import alfio.util.ExportUtils; import alfio.util.MonetaryUtil; import alfio.util.Validator; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; @@ -52,14 +53,22 @@ @RestController @RequestMapping("/admin/api") -@RequiredArgsConstructor -@Log4j2 public class AdditionalServiceApiController { + private static final Logger log = LoggerFactory.getLogger(AdditionalServiceApiController.class); + private final EventManager eventManager; private final EventRepository eventRepository; private final AdditionalServiceManager additionalServiceManager; + public AdditionalServiceApiController(EventManager eventManager, + EventRepository eventRepository, + AdditionalServiceManager additionalServiceManager) { + this.eventManager = eventManager; + this.eventRepository = eventRepository; + this.additionalServiceManager = additionalServiceManager; + } + @ExceptionHandler({IllegalArgumentException.class}) public ResponseEntity handleBadRequest(Exception e) { @@ -87,7 +96,7 @@ public List loadAll(@PathVariable("eventId" } @GetMapping("/event/{eventId}/additional-services/count") - public Map countUse(@PathVariable("eventId") int eventId) { + public Map> countUse(@PathVariable("eventId") int eventId) { return additionalServiceManager.countUsageForEvent(eventId); } @@ -155,6 +164,7 @@ public void exportAdditionalServices(@PathVariable("eventName") String eventName "Name", "Creation", "Last Update", + "Status", "Reservation ID", "Reservation First name", "Reservation Last name", @@ -171,6 +181,7 @@ public void exportAdditionalServices(@PathVariable("eventName") String eventName item.getAdditionalServiceTitle(), item.getUtcCreation().withZoneSameInstant(event.getZoneId()).format(formatter), requireNonNullElse(item.getUtcLastModified(), item.getUtcCreation()).withZoneSameInstant(event.getZoneId()).format(formatter), + item.getAdditionalServiceItemStatus().name(), item.getTicketsReservationUuid(), item.getFirstName(), item.getLastName(), diff --git a/src/main/java/alfio/controller/api/admin/AdminPaymentsApiController.java b/src/main/java/alfio/controller/api/admin/AdminPaymentsApiController.java new file mode 100644 index 0000000000..7350e7eb62 --- /dev/null +++ b/src/main/java/alfio/controller/api/admin/AdminPaymentsApiController.java @@ -0,0 +1,144 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.admin; + +import alfio.controller.api.support.PageAndContent; +import alfio.manager.PaymentManager; +import alfio.manager.PurchaseContextManager; +import alfio.manager.PurchaseContextSearchManager; +import alfio.manager.system.ConfigurationManager; +import alfio.model.PurchaseContext; +import alfio.model.ReservationPaymentDetail; +import alfio.model.modification.TransactionMetadataModification; +import alfio.model.system.ConfigurationKeys; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static alfio.util.ExportUtils.exportExcel; +import static java.util.Objects.requireNonNullElse; +import static org.apache.commons.lang3.StringUtils.trimToNull; + +@RestController +@RequestMapping("/admin/api/payments") +public class AdminPaymentsApiController { + + private static final String[] EXPORT_COLUMNS = new String[] { + "ID", + "Name", + "Email", + "Type", + "Amount", + "Currency", + "Payment Date/Time", + "Notes" + }; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private final PurchaseContextSearchManager purchaseContextSearchManager; + private final PurchaseContextManager purchaseContextManager; + private final PaymentManager paymentManager; + private final ConfigurationManager configurationManager; + + public AdminPaymentsApiController(PurchaseContextSearchManager purchaseContextSearchManager, + PurchaseContextManager purchaseContextManager, + PaymentManager paymentManager, + ConfigurationManager configurationManager) { + this.purchaseContextSearchManager = purchaseContextSearchManager; + this.purchaseContextManager = purchaseContextManager; + this.paymentManager = paymentManager; + this.configurationManager = configurationManager; + } + + @GetMapping("/{purchaseContextType}/{publicIdentifier}/list") + PageAndContent> getPaymentsForPurchaseContext(@PathVariable("purchaseContextType") PurchaseContext.PurchaseContextType purchaseContextType, + @PathVariable("publicIdentifier") String publicIdentifier, + @RequestParam(value = "page", required = false) Integer page, + @RequestParam(value = "search", required = false) String search, + Principal principal) { + return purchaseContextManager.findBy(purchaseContextType, publicIdentifier) + .filter(purchaseContext -> purchaseContextManager.validateAccess(purchaseContext, principal)) + .map(purchaseContext -> { + var res = purchaseContextSearchManager.findAllPaymentsFor(purchaseContext, page, search); + return new PageAndContent<>(res.getLeft(), res.getRight()); + }).orElseGet(() -> new PageAndContent<>(List.of(), 0)); + } + + @PutMapping("/{purchaseContextType}/{publicIdentifier}/reservation/{reservationId}") + ResponseEntity updateTransactionData(@PathVariable("purchaseContextType") PurchaseContext.PurchaseContextType purchaseContextType, + @PathVariable("publicIdentifier") String publicIdentifier, + @PathVariable("reservationId") String reservationId, + @RequestBody TransactionMetadataModification transactionMetadataModification, + Principal principal) { + try { + return ResponseEntity.of(purchaseContextManager.findBy(purchaseContextType, publicIdentifier) + .filter(purchaseContext -> purchaseContextManager.validateAccess(purchaseContext, principal)) + .map(purchaseContext -> { + var timestampModification = transactionMetadataModification.getTimestamp(); + var timestamp = timestampModification != null ? timestampModification.toZonedDateTime(purchaseContext.getZoneId()) : null; + paymentManager.updateTransactionDetails(reservationId, transactionMetadataModification.getNotes(), timestamp, principal); + return "OK"; + })); + } catch (IllegalArgumentException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); + } + } + + @GetMapping("/{purchaseContextType}/{publicIdentifier}/download") + void exportPayments(@PathVariable("purchaseContextType") PurchaseContext.PurchaseContextType purchaseContextType, + @PathVariable("publicIdentifier") String publicIdentifier, + @RequestParam(value = "search", required = false) String search, + Principal principal, + HttpServletResponse response) throws IOException { + var purchaseContextOptional = purchaseContextManager.findBy(purchaseContextType, publicIdentifier); + if (purchaseContextOptional.isPresent() && purchaseContextManager.validateAccess(purchaseContextOptional.get(), principal)) { + var purchaseContext = purchaseContextOptional.get(); + boolean useInvoiceNumber = configurationManager.getFor(ConfigurationKeys.USE_INVOICE_NUMBER_AS_ID, purchaseContext.getConfigurationLevel()) + .getValueAsBooleanOrDefault(); + var data = purchaseContextSearchManager.findAllPaymentsForExport(purchaseContext, search) + .stream() + .map(d -> new String[] { + useInvoiceNumber ? requireNonNullElse(trimToNull(d.getInvoiceNumber()), "N/A") : d.getId(), + d.getFirstName() + " " + d.getLastName(), + d.getEmail(), + d.getPaymentMethod(), + d.getPaidAmount(), + d.getCurrencyCode(), + formatTimestamp(purchaseContext, d.getTransactionTimestamp()), + d.getTransactionNotes() + }); + exportExcel(purchaseContext.getDisplayName()+" payments.xlsx", "Payments", EXPORT_COLUMNS, data, response); + } else { + response.setContentType("text/plain"); + response.setStatus(HttpStatus.PRECONDITION_REQUIRED.value()); + response.getWriter().write("No payments found"); + } + } + + private static String formatTimestamp(PurchaseContext purchaseContext, String timestamp) { + return ZonedDateTime.parse(timestamp) + .withZoneSameInstant(purchaseContext.getZoneId()) + .format(DATE_TIME_FORMATTER); + } +} diff --git a/src/main/java/alfio/controller/api/admin/AdminReservationApiController.java b/src/main/java/alfio/controller/api/admin/AdminReservationApiController.java index 798f3e3eef..f9414a7c63 100644 --- a/src/main/java/alfio/controller/api/admin/AdminReservationApiController.java +++ b/src/main/java/alfio/controller/api/admin/AdminReservationApiController.java @@ -16,6 +16,8 @@ */ package alfio.controller.api.admin; +import alfio.controller.api.support.BookingInfoTicket; +import alfio.controller.api.support.BookingInfoTicketLoader; import alfio.controller.api.support.PageAndContent; import alfio.manager.*; import alfio.model.*; @@ -24,9 +26,9 @@ import alfio.model.result.ErrorCode; import alfio.model.result.Result; import alfio.model.subscription.SubscriptionWithUsageDetails; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; -import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.springframework.http.ResponseEntity; @@ -44,7 +46,6 @@ @RequestMapping("/admin/api/reservation") @RestController -@AllArgsConstructor public class AdminReservationApiController { private final AdminReservationManager adminReservationManager; @@ -52,6 +53,21 @@ public class AdminReservationApiController { private final PurchaseContextManager purchaseContextManager; private final PurchaseContextSearchManager purchaseContextSearchManager; private final TicketReservationManager ticketReservationManager; + private final BookingInfoTicketLoader bookingInfoTicketLoader; + + public AdminReservationApiController(AdminReservationManager adminReservationManager, + EventManager eventManager, + PurchaseContextManager purchaseContextManager, + PurchaseContextSearchManager purchaseContextSearchManager, + TicketReservationManager ticketReservationManager, + BookingInfoTicketLoader bookingInfoTicketLoader) { + this.adminReservationManager = adminReservationManager; + this.eventManager = eventManager; + this.purchaseContextManager = purchaseContextManager; + this.purchaseContextSearchManager = purchaseContextSearchManager; + this.ticketReservationManager = ticketReservationManager; + this.bookingInfoTicketLoader = bookingInfoTicketLoader; + } @PostMapping("/{purchaseContextType}/{publicIdentifier}/new") public Result createNew(@PathVariable("purchaseContextType") PurchaseContextType purchaseContextType, @PathVariable("publicIdentifier") String publicIdentifier, @RequestBody AdminReservationModification reservation, Principal principal) { @@ -190,9 +206,21 @@ public Result loadTicket(@PathVariable("purchaseContextType") PurchaseCo ); } + @GetMapping("/{purchaseContextType}/{publicIdentifier}/{reservationId}/tickets-with-additional-data") + public List ticketsWithAdditionalData(@PathVariable("purchaseContextType") PurchaseContextType purchaseContextType, + @PathVariable("publicIdentifier") String publicIdentifier, + @PathVariable("reservationId") String reservationId) { + + if(purchaseContextType != PurchaseContextType.event) { + return List.of(); + } + + return adminReservationManager.getTicketIdsWithAdditionalData(purchaseContextType, publicIdentifier, reservationId); + } + @PostMapping("/event/{publicIdentifier}/{reservationId}/remove-tickets") - public Result removeTickets(@PathVariable("publicIdentifier") String publicIdentifier, + public Result removeTickets(@PathVariable("publicIdentifier") String publicIdentifier, @PathVariable("reservationId") String reservationId, @RequestBody RemoveTicketsModification toRemove, Principal principal) { @@ -202,8 +230,14 @@ public Result removeTickets(@PathVariable("publicIdentifier") String pu .map(Map.Entry::getKey) .collect(Collectors.toList()); - adminReservationManager.removeTickets(publicIdentifier, reservationId, toRemove.getTicketIds(), toRefund, toRemove.getNotify(), toRemove.getIssueCreditNote(), principal.getName()); - return Result.success(true); + boolean issueCreditNote = adminReservationManager.removeTickets(publicIdentifier, + reservationId, + toRemove.getTicketIds(), + toRefund, + toRemove.getNotify(), + toRemove.issueCreditNote, + principal.getName()).getData(); + return Result.success(new RemoveResult(true, issueCreditNote)); } @GetMapping("/{purchaseContextType}/{publicIdentifier}/{reservationId}/payment-info") @@ -244,6 +278,21 @@ public Result> getEmailList(@PathVariable("purchase return adminReservationManager.getEmailsForReservation(purchaseContextType, publicIdentifier, reservationId, principal.getName()); } + @GetMapping("/{purchaseContextType}/{publicIdentifier}/{reservationId}/ticket/{ticketId}/full-data") + public ResponseEntity loadFullTicketData(@PathVariable("purchaseContextType") PurchaseContextType purchaseContextType, + @PathVariable("publicIdentifier") String publicIdentifier, + @PathVariable("reservationId") String reservationId, + @PathVariable("ticketId") String ticketUUID) { + if(purchaseContextType != PurchaseContextType.event) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.of( + adminReservationManager.loadFullTicketInfo(reservationId, publicIdentifier, ticketUUID) + .map(eventAndTicket -> bookingInfoTicketLoader.toBookingInfoTicket(eventAndTicket.getRight(), eventAndTicket.getLeft())) + ); + } + private TicketReservationDescriptor toReservationDescriptor(String reservationId, Triple, PurchaseContext> triple) { List>> tickets = triple.getMiddle().stream().collect(Collectors.groupingBy(Ticket::getCategoryId)).entrySet().stream() .map(entry -> SerializablePair.of(eventManager.getTicketCategoryById(entry.getKey(), triple.getRight().event().orElseThrow().getId()), entry.getValue())) @@ -264,7 +313,6 @@ private SubscriptionWithUsageDetails buildSubscriptionDetails(PurchaseContext pu return null; } - @RequiredArgsConstructor @Getter public static class TicketReservationDescriptor { private final TicketReservation reservation; @@ -272,16 +320,39 @@ public static class TicketReservationDescriptor { private final OrderSummary orderSummary; private final List>> ticketsByCategory; private final SubscriptionWithUsageDetails subscriptionDetails; + + public TicketReservationDescriptor(TicketReservation reservation, + TicketReservationAdditionalInfo additionalInfo, + OrderSummary orderSummary, + List>> ticketsByCategory, + SubscriptionWithUsageDetails subscriptionDetails) { + this.reservation = reservation; + this.additionalInfo = additionalInfo; + this.orderSummary = orderSummary; + this.ticketsByCategory = ticketsByCategory; + this.subscriptionDetails = subscriptionDetails; + } } - @RequiredArgsConstructor + @Getter public static class RemoveTicketsModification { private final List ticketIds; - private Map refundTo; + private final Map refundTo; private final Boolean notify; private final Boolean issueCreditNote; + @JsonCreator + public RemoveTicketsModification(@JsonProperty("ticketIds") List ticketIds, + @JsonProperty("refundTo") Map refundTo, + @JsonProperty("notify") Boolean notify, + @JsonProperty("issueCreditNote") Boolean issueCreditNote) { + this.ticketIds = ticketIds; + this.refundTo = refundTo; + this.notify = notify; + this.issueCreditNote = issueCreditNote; + } + public Boolean getNotify() { return Boolean.TRUE.equals(notify); } @@ -291,9 +362,32 @@ public Boolean getIssueCreditNote() { } } - @RequiredArgsConstructor @Getter public static class RefundAmount { private final String amount; + + @JsonCreator + public RefundAmount(@JsonProperty("amount") String amount) { + this.amount = amount; + } + } + + public static class RemoveResult { + + private final boolean success; + private final boolean creditNoteGenerated; + + public RemoveResult(boolean success, boolean creditNoteGenerated) { + this.success = success; + this.creditNoteGenerated = creditNoteGenerated; + } + + public boolean isSuccess() { + return success; + } + + public boolean isCreditNoteGenerated() { + return creditNoteGenerated; + } } } diff --git a/src/main/java/alfio/controller/api/admin/AdminWaitingQueueApiController.java b/src/main/java/alfio/controller/api/admin/AdminWaitingQueueApiController.java index f5fca6044d..e8a31db344 100644 --- a/src/main/java/alfio/controller/api/admin/AdminWaitingQueueApiController.java +++ b/src/main/java/alfio/controller/api/admin/AdminWaitingQueueApiController.java @@ -29,8 +29,6 @@ import alfio.util.ClockProvider; import alfio.util.EventUtil; import alfio.util.ExportUtils; -import lombok.AllArgsConstructor; -import lombok.Data; import org.apache.commons.lang3.tuple.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -49,7 +47,6 @@ @RestController @RequestMapping("/admin/api/event/{eventName}/waiting-queue") -@AllArgsConstructor public class AdminWaitingQueueApiController { private final WaitingQueueManager waitingQueueManager; @@ -59,6 +56,20 @@ public class AdminWaitingQueueApiController { private final EventStatisticsManager eventStatisticsManager; private final ClockProvider clockProvider; + public AdminWaitingQueueApiController(WaitingQueueManager waitingQueueManager, + EventManager eventManager, + TicketReservationManager ticketReservationManager, + ConfigurationManager configurationManager, + EventStatisticsManager eventStatisticsManager, + ClockProvider clockProvider) { + this.waitingQueueManager = waitingQueueManager; + this.eventManager = eventManager; + this.ticketReservationManager = ticketReservationManager; + this.configurationManager = configurationManager; + this.eventStatisticsManager = eventStatisticsManager; + this.clockProvider = clockProvider; + } + @GetMapping("/status") public Map getStatusForEvent(@PathVariable("eventName") String eventName, Principal principal) { return eventManager.getOptionalByName(eventName, principal.getName()) @@ -168,9 +179,16 @@ private ResponseEntity> performStatusModification(String eve .orElseGet(() -> new ResponseEntity<>(HttpStatus.BAD_REQUEST)); } - @Data private static class SetStatusForm { private boolean status; + + public void setStatus(boolean status) { + this.status = status; + } + + public boolean isStatus() { + return status; + } } diff --git a/src/main/java/alfio/controller/api/admin/AttendeeBulkImportApiController.java b/src/main/java/alfio/controller/api/admin/AttendeeBulkImportApiController.java index 49da830bd2..ba258e2e4a 100644 --- a/src/main/java/alfio/controller/api/admin/AttendeeBulkImportApiController.java +++ b/src/main/java/alfio/controller/api/admin/AttendeeBulkImportApiController.java @@ -20,18 +20,20 @@ import alfio.model.AdminReservationRequestStats; import alfio.model.modification.AdminReservationModification; import alfio.model.result.Result; -import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import java.security.Principal; @RequestMapping("/admin/api/event/{eventName}/attendees/import") @RestController -@AllArgsConstructor public class AttendeeBulkImportApiController { private final AdminReservationRequestManager requestManager; + public AttendeeBulkImportApiController(AdminReservationRequestManager requestManager) { + this.requestManager = requestManager; + } + @PostMapping("") public Result createReservations(@PathVariable("eventName") String eventName, @RequestBody AdminReservationModification body, diff --git a/src/main/java/alfio/controller/api/admin/CheckInApiController.java b/src/main/java/alfio/controller/api/admin/CheckInApiController.java index 552bfef40d..a0a0f9bc4b 100644 --- a/src/main/java/alfio/controller/api/admin/CheckInApiController.java +++ b/src/main/java/alfio/controller/api/admin/CheckInApiController.java @@ -23,18 +23,18 @@ import alfio.manager.system.ConfigurationManager; import alfio.model.EventAndOrganizationId; import alfio.model.FullTicketInfo; +import alfio.model.checkin.AttendeeSearchResults; import alfio.model.system.ConfigurationKeys; import alfio.util.Json; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -46,26 +46,58 @@ import static alfio.util.Wrappers.optionally; -@Log4j2 @RestController @RequestMapping("/admin/api") -@RequiredArgsConstructor public class CheckInApiController { + private static final Logger log = LoggerFactory.getLogger(CheckInApiController.class); + private static final String ALFIO_TIMESTAMP_HEADER = "Alfio-TIME"; private final CheckInManager checkInManager; private final EventManager eventManager; private final ConfigurationManager configurationManager; - @Data + public CheckInApiController(CheckInManager checkInManager, + EventManager eventManager, + ConfigurationManager configurationManager) { + this.checkInManager = checkInManager; + this.eventManager = eventManager; + this.configurationManager = configurationManager; + } + + public static class TicketCode { private String code; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } } - @Data + public static class TicketIdentifierCode { private String identifier; private String code; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } } @GetMapping("/check-in/{eventId}/ticket/{ticketIdentifier}") @@ -120,18 +152,34 @@ public Map bulkCheckIn(@PathVariable("eventName" public boolean manualCheckIn(@PathVariable("eventId") int eventId, @PathVariable("ticketIdentifier") String ticketIdentifier, Principal principal) { - log.warn("for event id : {} and ticket : {}, a manual check in has been done", eventId, ticketIdentifier); + log.warn("for event id : {} and ticket : {}, a manual check in has been done by {}", eventId, ticketIdentifier, principal.getName()); return checkInManager.manualCheckIn(eventId, ticketIdentifier, principal.getName()); } + @PostMapping("/check-in/event/{eventName}/ticket/{ticketIdentifier}/manual-check-in") + public ResponseEntity manualCheckIn(@PathVariable("eventName") String eventName, + @PathVariable("ticketIdentifier") String ticketIdentifier, + Principal principal) { + return ResponseEntity.of(eventManager.getOptionalEventAndOrganizationIdByName(eventName, principal.getName()) + .map(ev -> manualCheckIn(ev.getId(), ticketIdentifier, principal))); + } + @PostMapping("/check-in/{eventId}/ticket/{ticketIdentifier}/revert-check-in") public boolean revertCheckIn(@PathVariable("eventId") int eventId, @PathVariable("ticketIdentifier") String ticketIdentifier, Principal principal) { - log.warn("for event id : {} and ticket : {}, a revert of the check in has been done", eventId, ticketIdentifier); + log.warn("for event id : {} and ticket : {}, a revert of the check in has been done by {}", eventId, ticketIdentifier, principal.getName()); return checkInManager.revertCheckIn(eventId, ticketIdentifier, principal.getName()); } + @PostMapping("/check-in/event/{eventName}/ticket/{ticketIdentifier}/revert-check-in") + public ResponseEntity revertCheckIn(@PathVariable("eventName") String eventName, + @PathVariable("ticketIdentifier") String ticketIdentifier, + Principal principal) { + return ResponseEntity.of(eventManager.getOptionalEventAndOrganizationIdByName(eventName, principal.getName()) + .map(ev -> revertCheckIn(ev.getId(), ticketIdentifier, principal))); + } + @PostMapping("/check-in/event/{eventName}/ticket/{ticketIdentifier}/confirm-on-site-payment") public TicketAndCheckInResult confirmOnSitePayment(@PathVariable("eventName") String eventName, @PathVariable("ticketIdentifier") String ticketIdentifier, @@ -164,6 +212,20 @@ public List findAllIdentifiersForAdminCheckIn(@PathVariable("eventId") return checkInManager.getAttendeesIdentifiers(eventId, changedSince == null ? new Date(0) : new Date(changedSince), principal.getName()); } + @GetMapping("/check-in/event/{publicIdentifier}/attendees") + public ResponseEntity searchAttendees(@PathVariable("publicIdentifier") String publicIdentifier, + @RequestParam(value = "query", required = false) String query, + @RequestParam(value = "page", required = false, defaultValue = "0") int page, + Principal principal) { + if (StringUtils.isBlank(query) || StringUtils.isBlank(publicIdentifier)) { + return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); + } + + return ResponseEntity.of(eventManager.getOptionalByName(publicIdentifier, principal.getName()) + .map(event -> checkInManager.searchAttendees(event, query, page))); + + } + @PostMapping("/check-in/{eventId}/tickets") public List findAllTicketsForAdminCheckIn(@PathVariable("eventId") int eventId, @RequestBody List ids, @@ -239,10 +301,8 @@ private Optional loadLabelLayout(EventAndOrganizationId event) { .flatMap(str -> optionally(() -> Json.fromJson(str, LabelLayout.class))); } - @Data - private static class OnSitePaymentConfirmation { - private final boolean status; - private final String message; + + private record OnSitePaymentConfirmation(@JsonProperty("status") boolean status, @JsonProperty("message") String message) { } @Getter diff --git a/src/main/java/alfio/controller/api/admin/ConfigurationApiController.java b/src/main/java/alfio/controller/api/admin/ConfigurationApiController.java index 2851856d0e..db2b37861f 100644 --- a/src/main/java/alfio/controller/api/admin/ConfigurationApiController.java +++ b/src/main/java/alfio/controller/api/admin/ConfigurationApiController.java @@ -29,11 +29,8 @@ import alfio.model.modification.ConfigurationModification; import alfio.model.system.Configuration; import alfio.model.system.ConfigurationKeys; -import alfio.model.user.Organization; import alfio.util.ClockProvider; import alfio.util.RequestUtils; -import lombok.AllArgsConstructor; -import lombok.Data; import org.apache.commons.lang3.tuple.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -52,7 +49,6 @@ @RestController @RequestMapping("/admin/api/configuration") -@AllArgsConstructor public class ConfigurationApiController { private final ConfigurationManager configurationManager; @@ -62,6 +58,20 @@ public class ConfigurationApiController { private final ClockProvider clockProvider; private final UserManager userManager; + public ConfigurationApiController(ConfigurationManager configurationManager, + BillingDocumentManager billingDocumentManager, + AdminJobManager adminJobManager, + EventManager eventManager, + ClockProvider clockProvider, + UserManager userManager) { + this.configurationManager = configurationManager; + this.billingDocumentManager = billingDocumentManager; + this.adminJobManager = adminJobManager; + this.eventManager = eventManager; + this.clockProvider = clockProvider; + this.userManager = userManager; + } + @GetMapping(value = "/load") public Map> loadConfiguration(Principal principal) { return configurationManager.loadAllSystemConfigurationIncludingMissing(principal.getName()); @@ -266,15 +276,6 @@ public ResponseEntity generateTicketsForSubscriptions(@RequestParam(val return ResponseEntity.ok(adminJobManager.scheduleExecution(ASSIGN_TICKETS_TO_SUBSCRIBERS, requireNonNullElse(jobMetadata, Map.of()))); } - @Data - static class OrganizationConfig { - private final Organization organization; - private final Map> config; - } - - @Data - static class InstanceSettings { - private final int descriptionMaxLength; - private final String baseUrl; + record InstanceSettings(int descriptionMaxLength, String baseUrl) { } } diff --git a/src/main/java/alfio/controller/api/admin/CustomMessagesApiController.java b/src/main/java/alfio/controller/api/admin/CustomMessagesApiController.java index cf8a18c949..be8919879e 100644 --- a/src/main/java/alfio/controller/api/admin/CustomMessagesApiController.java +++ b/src/main/java/alfio/controller/api/admin/CustomMessagesApiController.java @@ -18,7 +18,8 @@ import alfio.manager.support.CustomMessageManager; import alfio.model.modification.MessageModification; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -30,9 +31,10 @@ @RestController @RequestMapping("/admin/api/events/{eventName}/messages") -@Log4j2 public class CustomMessagesApiController { + private static final Logger log = LoggerFactory.getLogger(CustomMessagesApiController.class); + private final CustomMessageManager customMessageManager; @Autowired diff --git a/src/main/java/alfio/controller/api/admin/EmailMessageApiController.java b/src/main/java/alfio/controller/api/admin/EmailMessageApiController.java index 5e01d18c89..0120b42012 100644 --- a/src/main/java/alfio/controller/api/admin/EmailMessageApiController.java +++ b/src/main/java/alfio/controller/api/admin/EmailMessageApiController.java @@ -22,8 +22,6 @@ import alfio.model.EmailMessage; import alfio.model.LightweightMailMessage; import alfio.model.PurchaseContext; -import lombok.AllArgsConstructor; -import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -36,7 +34,6 @@ import java.util.Optional; import java.util.stream.Collectors; -@RequiredArgsConstructor @RestController @RequestMapping("/admin/api/{purchaseContextType}/{publicIdentifier}/email") public class EmailMessageApiController { @@ -44,6 +41,12 @@ public class EmailMessageApiController { private final NotificationManager notificationManager; private final PurchaseContextManager purchaseContextManager; + public EmailMessageApiController(NotificationManager notificationManager, + PurchaseContextManager purchaseContextManager) { + this.notificationManager = notificationManager; + this.purchaseContextManager = purchaseContextManager; + } + @GetMapping("/") public PageAndContent> loadEmailMessages(@PathVariable("purchaseContextType") PurchaseContext.PurchaseContextType purchaseContextType, @PathVariable("publicIdentifier") String publicIdentifier, @@ -67,13 +70,19 @@ public LightweightEmailMessage loadEmailMessage(@PathVariable("purchaseContextTy return notificationManager.loadSingleMessageForPurchaseContext(purchaseContext, messageId).map(m -> new LightweightEmailMessage(m, purchaseContext.getZoneId(), false)).orElseThrow(IllegalArgumentException::new); } - @AllArgsConstructor + private static final class LightweightEmailMessage { @Delegate(excludes = LightweightExclusions.class) private final EmailMessage src; private final ZoneId eventZoneId; private final boolean list; + private LightweightEmailMessage(EmailMessage src, ZoneId eventZoneId, boolean list) { + this.src = src; + this.eventZoneId = eventZoneId; + this.list = list; + } + public String getAttachments() { return null; } diff --git a/src/main/java/alfio/controller/api/admin/EventApiController.java b/src/main/java/alfio/controller/api/admin/EventApiController.java index fb724dc40e..0b708e17e7 100644 --- a/src/main/java/alfio/controller/api/admin/EventApiController.java +++ b/src/main/java/alfio/controller/api/admin/EventApiController.java @@ -45,16 +45,13 @@ import alfio.util.*; import com.opencsv.CSVReader; import com.opencsv.exceptions.CsvException; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -87,15 +84,14 @@ import static alfio.util.Validator.*; import static alfio.util.Wrappers.optionally; import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.stream.Collectors.toList; import static org.apache.commons.lang3.StringUtils.defaultString; @RestController @RequestMapping("/admin/api") -@Log4j2 -@AllArgsConstructor public class EventApiController { + private static final Logger log = LoggerFactory.getLogger(EventApiController.class); + private static final String OK = "OK"; private static final String CUSTOM_FIELDS_PREFIX = "custom:"; private final EventManager eventManager; @@ -115,6 +111,40 @@ public class EventApiController { private final ExtensionManager extensionManager; private final ClockProvider clockProvider; + public EventApiController(EventManager eventManager, + EventStatisticsManager eventStatisticsManager, + I18nManager i18nManager, + TicketReservationManager ticketReservationManager, + TicketFieldRepository ticketFieldRepository, + EventDescriptionRepository eventDescriptionRepository, + TicketHelper ticketHelper, + DynamicFieldTemplateRepository dynamicFieldTemplateRepository, + UserManager userManager, + SponsorScanRepository sponsorScanRepository, + PaymentManager paymentManager, + TemplateManager templateManager, + FileUploadManager fileUploadManager, + ConfigurationManager configurationManager, + ExtensionManager extensionManager, + ClockProvider clockProvider) { + this.eventManager = eventManager; + this.eventStatisticsManager = eventStatisticsManager; + this.i18nManager = i18nManager; + this.ticketReservationManager = ticketReservationManager; + this.ticketFieldRepository = ticketFieldRepository; + this.eventDescriptionRepository = eventDescriptionRepository; + this.ticketHelper = ticketHelper; + this.dynamicFieldTemplateRepository = dynamicFieldTemplateRepository; + this.userManager = userManager; + this.sponsorScanRepository = sponsorScanRepository; + this.paymentManager = paymentManager; + this.templateManager = templateManager; + this.fileUploadManager = fileUploadManager; + this.configurationManager = configurationManager; + this.extensionManager = extensionManager; + this.clockProvider = clockProvider; + } + @ExceptionHandler(DataAccessException.class) public String exception(DataAccessException e) { @@ -142,13 +172,15 @@ public List getPaymentProxies( @PathVariable("o } @GetMapping(value = "/events", headers = "Authorization") - public List getAllEventsForExternal(Principal principal, HttpServletRequest request) { - List userOrganizations = userManager.findUserOrganizations(principal.getName()).stream().map(Organization::getId).collect(toList()); + public List getAllEventsForExternal(Principal principal, + HttpServletRequest request, + @RequestParam(value = "includeOnline", required = false, defaultValue = "false") boolean includeOnline) { + List userOrganizations = userManager.findUserOrganizations(principal.getName()).stream().map(Organization::getId).toList(); return eventManager.getActiveEvents().stream() - .filter(e -> userOrganizations.contains(e.getOrganizationId())) + .filter(e -> userOrganizations.contains(e.getOrganizationId()) && (includeOnline || e.getFormat() != Event.EventFormat.ONLINE)) .sorted(Comparator.comparing(e -> e.getBegin().withZoneSameInstant(ZoneId.systemDefault()))) .map(s -> new EventListItem(s, request.getContextPath(), eventDescriptionRepository.findByEventId(s.getId()))) - .collect(toList()); + .toList(); } @GetMapping("/events") @@ -156,6 +188,12 @@ public List getAllEvents(Principal principal) { return eventStatisticsManager.getAllEventsWithStatistics(principal.getName()); } + @GetMapping("/events-count") + public ResponseEntity getEventsCount() { + return ResponseEntity.ok(eventManager.getEventsCount()); + } + + @GetMapping("/active-events") public List getAllActiveEvents(Principal principal) { return eventStatisticsManager.getAllEventsWithStatisticsFilteredBy(principal.getName(), event -> !event.expiredSince(14)); @@ -170,11 +208,7 @@ public List getAllExpiredEvents(Principal principal) { } - @AllArgsConstructor - @Getter - public static class EventAndOrganization { - private final EventWithAdditionalInfo event; - private final Organization organization; + public record EventAndOrganization(EventWithAdditionalInfo event, Organization organization) { } @@ -310,8 +344,8 @@ public ResponseEntity rearrangeCategories(@PathVariable("eventName") Str } private static final String PAYMENT_METHOD = "Payment Method"; - private static final List FIXED_FIELDS = Arrays.asList("ID", "Category", "Event", "Status", "OriginalPrice", "PaidPrice", "Discount", "VAT", "ReservationID", "Full Name", "First Name", "Last Name", "E-Mail", "Locked", "Language", "Confirmation", "Billing Address", "Country Code", "Payment ID", PAYMENT_METHOD); - private static final List> FIXED_PAIRS = FIXED_FIELDS.stream().map(f -> SerializablePair.of(f, f)).collect(toList()); + private static final List FIXED_FIELDS = Arrays.asList("ID", "Category", "Event", "Status", "OriginalPrice", "PaidPrice", "Discount", "VAT", "ReservationID", "Full Name", "First Name", "Last Name", "E-Mail", "Locked", "Language", "Confirmation", "Billing Address", "Country Code", "Voucher Code", "Payment ID", PAYMENT_METHOD); + private static final List> FIXED_PAIRS = FIXED_FIELDS.stream().map(f -> SerializablePair.of(f, f)).toList(); private static final String FISCAL_CODE = "Fiscal Code"; private static final String REFERENCE_TYPE = "Reference Type"; private static final List ITALIAN_E_INVOICING_FIELDS = List.of(FISCAL_CODE, REFERENCE_TYPE, "Addressee Code", "PEC"); @@ -381,6 +415,7 @@ private Stream exportLines(String eventName, Principal principal, List if(fields.contains("Confirmation")) {line.add(reservation.getConfirmationTimestamp().withZoneSameInstant(eventZoneId).toString());} if(fields.contains("Billing Address")) {line.add(reservation.getBillingAddress());} if(fields.contains("Country Code")) {line.add(reservation.getVatCountryCode());} + if(fields.contains("Voucher Code")) {line.add(trs.getPromoCode());} boolean paymentIdRequested = fields.contains("Payment ID"); boolean paymentGatewayRequested = fields.contains(PAYMENT_METHOD); if((paymentIdRequested || paymentGatewayRequested)) { @@ -423,9 +458,10 @@ public void downloadSponsorScanExport(@PathVariable("eventName") String eventNam header.add("Timestamp"); header.add("Full name"); header.add("Email"); - header.addAll(fields.stream().map(TicketFieldConfiguration::getName).collect(toList())); + header.addAll(fields.stream().map(TicketFieldConfiguration::getName).toList()); header.add("Sponsor notes"); header.add("Lead Status"); + header.add("Operator"); Stream sponsorScans = userManager.findAllEnabledUsers(principal.getName()).stream() .map(u -> Pair.of(u, userManager.getUserRole(u))) @@ -436,12 +472,12 @@ public void downloadSponsorScanExport(@PathVariable("eventName") String eventNam .map(p -> { DetailedScanData data = p.getLeft(); Map descriptions = p.getRight(); - return Pair.of(data, fields.stream().map(x -> descriptions.getOrDefault(x.getName(), "")).collect(toList())); + return Pair.of(data, fields.stream().map(x -> descriptions.getOrDefault(x.getName(), "")).toList()); }).map(p -> { List line = new ArrayList<>(); Ticket ticket = p.getLeft().getTicket(); SponsorScan sponsorScan = p.getLeft().getSponsorScan(); - User user = userManager.findUser(sponsorScan.getUserId()); + User user = userManager.findUser(sponsorScan.getUserId(), principal); line.add(user.getUsername()); line.add(user.getDescription()); line.add(sponsorScan.getTimestamp().toString()); @@ -452,6 +488,7 @@ public void downloadSponsorScanExport(@PathVariable("eventName") String eventNam line.add(sponsorScan.getNotes()); line.add(sponsorScan.getLeadStatus().name()); + line.add(sponsorScan.getOperator()); return line.toArray(new String[0]); }); @@ -480,9 +517,9 @@ public List> getAllFields(@PathVariable("eventN var eventAndOrganizationId = eventManager.getEventAndOrganizationId(eventName, principal.getName()); List> fields = new ArrayList<>(FIXED_PAIRS); if(configurationManager.isItalianEInvoicingEnabled(eventAndOrganizationId)) { - fields.addAll(ITALIAN_E_INVOICING_FIELDS.stream().map(f -> SerializablePair.of(f, f)).collect(toList())); + fields.addAll(ITALIAN_E_INVOICING_FIELDS.stream().map(f -> SerializablePair.of(f, f)).toList()); } - fields.addAll(ticketFieldRepository.findFieldsForEvent(eventName).stream().map(f -> SerializablePair.of(CUSTOM_FIELDS_PREFIX + f, f)).collect(toList())); + fields.addAll(ticketFieldRepository.findFieldsForEvent(eventName).stream().map(f -> SerializablePair.of(CUSTOM_FIELDS_PREFIX + f, f)).toList()); return fields; } @@ -491,7 +528,7 @@ public List getAllAdditionalField(@P final Map> descById = ticketFieldRepository.findDescriptions(eventName).stream().collect(Collectors.groupingBy(TicketFieldDescription::getTicketFieldConfigurationId)); return ticketFieldRepository.findAdditionalFieldsForEvent(eventName).stream() .map(field -> new TicketFieldConfigurationAndAllDescriptions(field, descById.getOrDefault(field.getId(), Collections.emptyList()))) - .collect(toList()); + .toList(); } @GetMapping("/events/{eventName}/additional-field/{id}/stats") @@ -561,9 +598,12 @@ public Integer getPendingPaymentsCount(@PathVariable("eventName") String eventNa } @PostMapping("/events/{eventName}/pending-payments/{reservationId}/confirm") - public String confirmPayment(@PathVariable("eventName") String eventName, @PathVariable("reservationId") String reservationId, Principal principal) { + public String confirmPayment(@PathVariable("eventName") String eventName, + @PathVariable("reservationId") String reservationId, + @RequestBody TransactionMetadataModification transactionMetadataModification, + Principal principal) { var event = loadEvent(eventName, principal); - ticketReservationManager.confirmOfflinePayment(event, reservationId, principal.getName()); + ticketReservationManager.confirmOfflinePayment(event, reservationId, transactionMetadataModification, principal.getName()); ticketReservationManager.findById(reservationId) .filter(TicketReservation::isDirectAssignmentRequested) .ifPresent(reservation -> { @@ -577,8 +617,9 @@ public String confirmPayment(@PathVariable("eventName") String eventName, @PathV public String deletePendingPayment(@PathVariable("eventName") String eventName, @PathVariable("reservationId") String reservationId, @RequestParam(required = false, value = "credit", defaultValue = "false") Boolean creditReservation, + @RequestParam(required = false, value = "notify", defaultValue = "true") Boolean notify, Principal principal) { - ticketReservationManager.deleteOfflinePayment(loadEvent(eventName, principal), reservationId, false, Boolean.TRUE.equals(creditReservation), principal.getName()); + ticketReservationManager.deleteOfflinePayment(loadEvent(eventName, principal), reservationId, false, Boolean.TRUE.equals(creditReservation), notify, principal.getName()); return OK; } @@ -601,7 +642,7 @@ public List> bulkConfirmation(@PathVariable("eve return Triple.of(Boolean.FALSE, Optional.ofNullable(reservationID).orElse(""), e.getMessage()); } }) - .collect(toList()); + .toList(); } } @@ -619,9 +660,9 @@ public List getAvailableLocales(@PathVariable("eventName") Stri } @GetMapping("/events/{eventName}/invoices/count") - public Integer countInvoicesForEvent(@PathVariable("eventName") String eventName, Principal principal) { + public Integer countBillingDocumentsForEvent(@PathVariable("eventName") String eventName, Principal principal) { return eventManager.getOptionalEventAndOrganizationIdByName(eventName, principal.getName()) - .map(e -> ticketReservationManager.countInvoices(e.getId())) + .map(e -> ticketReservationManager.countBillingDocuments(e.getId())) .orElse(0); } @@ -643,29 +684,30 @@ public void getAllInvoices(@PathVariable("eventName") String eventName, HttpServ } } - @SneakyThrows private void addPdfToZip(Event event, ZipOutputStream zipOS, TicketReservation reservation, BillingDocument document) { Map reservationModel = document.getModel(); Optional pdf; var language = LocaleUtil.forLanguageTag(reservation.getUserLanguage()); - switch(document.getType()) { - case CREDIT_NOTE: - pdf = TemplateProcessor.buildCreditNotePdf(event, fileUploadManager, language, templateManager, reservationModel, extensionManager); - break; - case RECEIPT: - pdf = TemplateProcessor.buildReceiptPdf(event, fileUploadManager, language, templateManager, reservationModel, extensionManager); - break; - default: - pdf = TemplateProcessor.buildInvoicePdf(event, fileUploadManager, language, templateManager, reservationModel, extensionManager); - } + pdf = switch (document.getType()) { + case CREDIT_NOTE -> + TemplateProcessor.buildCreditNotePdf(event, fileUploadManager, language, templateManager, reservationModel, extensionManager); + case RECEIPT -> + TemplateProcessor.buildReceiptPdf(event, fileUploadManager, language, templateManager, reservationModel, extensionManager); + default -> + TemplateProcessor.buildInvoicePdf(event, fileUploadManager, language, templateManager, reservationModel, extensionManager); + }; if (pdf.isPresent()) { String fileName = FileUtil.getBillingDocumentFileName(event.getShortName(), reservation.getId(), document); var entry = new ZipEntry(fileName); entry.setTimeLocal(document.getGenerationTimestamp().withZoneSameInstant(event.getZoneId()).toLocalDateTime()); - zipOS.putNextEntry(entry); - StreamUtils.copy(pdf.get(), zipOS); + try { + zipOS.putNextEntry(entry); + StreamUtils.copy(pdf.get(), zipOS); + } catch (IOException e) { + throw new IllegalStateException(e); + } } } @@ -861,11 +903,9 @@ private Event loadEvent(String eventName, Principal principal) { return singleEvent.orElseThrow(); } - @Data - static class TicketsStatistics { - private final String granularity; - private final List sold; - private final List reserved; + record TicketsStatistics(String granularity, + List sold, + List reserved) { } } diff --git a/src/main/java/alfio/controller/api/admin/ExportApiController.java b/src/main/java/alfio/controller/api/admin/ExportApiController.java new file mode 100644 index 0000000000..70ed2c1c7d --- /dev/null +++ b/src/main/java/alfio/controller/api/admin/ExportApiController.java @@ -0,0 +1,141 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.admin; + +import alfio.manager.ExportManager; +import alfio.model.ReservationsByEvent; +import alfio.model.support.ReservationInfo; +import alfio.model.support.TicketInfo; +import alfio.util.MonetaryUtil; +import ch.digitalfondue.basicxlsx.StreamingWorkbook; +import ch.digitalfondue.basicxlsx.Style; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.time.LocalDate; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Stream; + +import static alfio.util.ExportUtils.addSheetToWorkbook; +import static alfio.util.ExportUtils.exportExcel; +import static java.util.Objects.*; + +@RestController +@RequestMapping("/admin/api/export") +public class ExportApiController { + + private final ExportManager exportManager; + + public ExportApiController(ExportManager exportManager) { + this.exportManager = exportManager; + } + + @GetMapping("/reservations") + public void downloadAllEvents(@RequestParam(name = "from") String from, + @RequestParam(name = "to") String to, + HttpServletResponse response, + Principal principal) throws IOException { + var allEvents = exportManager.reservationsForInterval(LocalDate.parse(requireNonNull(from)), + LocalDate.parse(requireNonNull(to)), requireNonNull(principal)); + if (allEvents.isEmpty()) { + response.setContentType("text/plain"); + response.setStatus(HttpStatus.PRECONDITION_REQUIRED.value()); + response.getWriter().write("No reservations found for the selected period"); + } else { + exportExcel("all-reservations.xlsx", response, workbook -> writeSheets(allEvents, workbook)); + } + } + + private static void writeSheets(List allEvents, StreamingWorkbook workbook) { + var header = new String[] { + "Event Name", + "Reservation ID", + "Confirmation Date", + "Billed to", + "Tax ID", + "Tax Code", + "Invoice #", + "Amount", + "Tax", + "Currency", + "Payment Type", + "Ticket ID", + "Ticket Type", + "Ticket Amount", + "Ticket Tax", + "Attendee", + "Status" + }; + var headerStyle = workbook.defineStyle().font().bold(true).build(); + allEvents.stream().sorted(Comparator.comparing(ReservationsByEvent::getEventShortName)) + .forEach(e -> addSheet(workbook, header, headerStyle, e)); + } + + private static void addSheet(StreamingWorkbook workbook, String[] header, Style headerStyle, ReservationsByEvent eventWithReservations) { + var rowData = eventWithReservations.getReservations().stream() + .sorted(Comparator.comparing(ReservationInfo::getConfirmationTimestamp)) + .flatMap(r -> ticketRows(eventWithReservations, r)); + addSheetToWorkbook(eventWithReservations.getEventShortName(), header, rowData, workbook, headerStyle); + } + + private static Stream ticketRows(ReservationsByEvent eventWithReservations, ReservationInfo r) { + return r.getTickets().stream() + .map(t -> buildTicketRow(eventWithReservations, r, t)); + } + + private static String[] buildTicketRow(ReservationsByEvent eventWithReservations, + ReservationInfo r, + TicketInfo t) { + return new String[]{ + eventWithReservations.getDisplayName(), + r.getId(), + r.getConfirmationTimestamp(), + billingCompanyOrFullName(r), + r.getTaxId(), + r.getTaxCode(), + r.getInvoiceNumber(), + formatAmount(r.getSrcPriceCts(), r.getCurrency()), + formatAmount(r.getTaxCts(), r.getCurrency()), + r.getCurrency(), + r.getPaymentType().name(), + t.getId(), + t.getType(), + formatAmount(t.getSrcPriceCts(), r.getCurrency()), + formatAmount(t.getTaxCts(), r.getCurrency()), + (requireNonNullElse(t.getFirstName(), "") + " " + requireNonNullElse(t.getLastName(), "")).trim(), + t.getStatus() + }; + } + + private static String billingCompanyOrFullName(ReservationInfo r) { + return requireNonNullElseGet(r.getCompanyName(), () -> r.getFirstName() + " " + r.getLastName()); + } + + private static String formatAmount(Integer originalCts, String currency) { + if (originalCts == null) { + return ""; + } + return MonetaryUtil.formatCents(originalCts, currency); + } +} diff --git a/src/main/java/alfio/controller/api/admin/ExtensionApiController.java b/src/main/java/alfio/controller/api/admin/ExtensionApiController.java index be8f83a57e..4c14c66a34 100644 --- a/src/main/java/alfio/controller/api/admin/ExtensionApiController.java +++ b/src/main/java/alfio/controller/api/admin/ExtensionApiController.java @@ -30,11 +30,11 @@ import alfio.model.user.User; import alfio.repository.EventRepository; import alfio.repository.user.OrganizationRepository; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.http.ResponseEntity; import org.springframework.util.StreamUtils; @@ -51,11 +51,11 @@ import java.util.stream.Collectors; @RestController -@AllArgsConstructor @RequestMapping("/admin/api/extensions") -@Log4j2 public class ExtensionApiController { + private static final Logger log = LoggerFactory.getLogger(ExtensionApiController.class); + private static final String SAMPLE_JS; @@ -72,6 +72,16 @@ public class ExtensionApiController { private final OrganizationRepository organizationRepository; private final EventRepository eventRepository; + public ExtensionApiController(ExtensionService extensionService, + UserManager userManager, + OrganizationRepository organizationRepository, + EventRepository eventRepository) { + this.extensionService = extensionService; + this.userManager = userManager; + this.organizationRepository = organizationRepository; + this.eventRepository = eventRepository; + } + @GetMapping("") public List listAll(Principal principal) { diff --git a/src/main/java/alfio/controller/api/admin/FileUploadApiController.java b/src/main/java/alfio/controller/api/admin/FileUploadApiController.java index 30c5a63c7e..4120c8e067 100644 --- a/src/main/java/alfio/controller/api/admin/FileUploadApiController.java +++ b/src/main/java/alfio/controller/api/admin/FileUploadApiController.java @@ -18,29 +18,20 @@ import alfio.manager.FileUploadManager; import alfio.model.modification.UploadBase64FileModification; -import lombok.extern.log4j.Log4j2; - -import org.imgscalr.Scalr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.util.MimeType; -import org.springframework.util.MimeTypeUtils; -import org.springframework.web.bind.annotation.*; - -import javax.imageio.ImageIO; - -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/admin/api") -@Log4j2 public class FileUploadApiController { - private static final int IMAGE_THUMB_MAX_WIDTH_PX = 500; - private static final int IMAGE_THUMB_MAX_HEIGHT_PX = 500; + private static final Logger log = LoggerFactory.getLogger(FileUploadApiController.class); private final FileUploadManager fileUploadManager; @@ -50,36 +41,12 @@ public FileUploadApiController(FileUploadManager fileUploadManager) { } @PostMapping("/file/upload") - public ResponseEntity uploadFile(@RequestParam(required = false, value = "resizeImage", defaultValue = "false") Boolean resizeImage, - @RequestBody UploadBase64FileModification upload) { - + public ResponseEntity uploadFile(@RequestBody UploadBase64FileModification upload) { try { - final var mimeType = MimeTypeUtils.parseMimeType(upload.getType()); - if (Boolean.TRUE.equals(resizeImage)) { - upload = resize(upload, mimeType); - } return ResponseEntity.ok(fileUploadManager.insertFile(upload)); } catch (Exception e) { log.error("error while uploading image", e); return ResponseEntity.badRequest().build(); } } - - private UploadBase64FileModification resize(UploadBase64FileModification upload, MimeType mimeType) throws IOException { - BufferedImage image = ImageIO.read(new ByteArrayInputStream(upload.getFile())); - //resize only if the image is bigger than 500px on one of the side - if (image.getWidth() > IMAGE_THUMB_MAX_WIDTH_PX || image.getHeight() > IMAGE_THUMB_MAX_HEIGHT_PX) { - UploadBase64FileModification resized = new UploadBase64FileModification(); - BufferedImage thumbImg = Scalr.resize(image, Scalr.Method.QUALITY, Scalr.Mode.AUTOMATIC, IMAGE_THUMB_MAX_WIDTH_PX, IMAGE_THUMB_MAX_HEIGHT_PX, Scalr.OP_ANTIALIAS); - try (final var baos = new ByteArrayOutputStream()) { - ImageIO.write(thumbImg, mimeType.getSubtype(), baos); - resized.setFile(baos.toByteArray()); - } - resized.setAttributes(upload.getAttributes()); - resized.setName(upload.getName()); - resized.setType(upload.getType()); - return resized; - } - return upload; - } } diff --git a/src/main/java/alfio/controller/api/admin/GroupApiController.java b/src/main/java/alfio/controller/api/admin/GroupApiController.java index 8c832a4f6c..38cf74525f 100644 --- a/src/main/java/alfio/controller/api/admin/GroupApiController.java +++ b/src/main/java/alfio/controller/api/admin/GroupApiController.java @@ -26,7 +26,6 @@ import alfio.model.modification.LinkedGroupModification; import alfio.model.result.ErrorCode; import alfio.model.result.Result; -import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -39,13 +38,20 @@ @RestController @RequestMapping("/admin/api/group") -@RequiredArgsConstructor public class GroupApiController { private final GroupManager groupManager; private final UserManager userManager; private final EventManager eventManager; + public GroupApiController(GroupManager groupManager, + UserManager userManager, + EventManager eventManager) { + this.groupManager = groupManager; + this.userManager = userManager; + this.eventManager = eventManager; + } + @ExceptionHandler(DuplicateGroupItemException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleDuplicateGroupItemException(DuplicateGroupItemException exc) { diff --git a/src/main/java/alfio/controller/api/admin/LocationApiController.java b/src/main/java/alfio/controller/api/admin/LocationApiController.java index 3fb233d56c..97dc44ae91 100644 --- a/src/main/java/alfio/controller/api/admin/LocationApiController.java +++ b/src/main/java/alfio/controller/api/admin/LocationApiController.java @@ -21,9 +21,9 @@ import alfio.model.modification.support.LocationDescriptor; import alfio.model.system.ConfigurationKeys; import com.moodysalem.TimezoneMapper; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -35,9 +35,10 @@ @RestController @RequestMapping("/admin/api") -@Log4j2 public class LocationApiController { + private static final Logger log = LoggerFactory.getLogger(LocationApiController.class); + private final ConfigurationManager configurationManager; @Autowired @@ -88,10 +89,15 @@ public ProviderAndKeys getGeoInfoProviderAndKeys() { return new ProviderAndKeys(provider, apiKeys); } - @AllArgsConstructor + @Getter public static class ProviderAndKeys { private final ConfigurationKeys.GeoInfoProvider provider; - private Map keys; + private final Map keys; + + public ProviderAndKeys(GeoInfoProvider provider, Map keys) { + this.provider = provider; + this.keys = keys; + } } } diff --git a/src/main/java/alfio/controller/api/admin/PollAdminApiController.java b/src/main/java/alfio/controller/api/admin/PollAdminApiController.java index 44ca9c318e..228d9cf0d1 100644 --- a/src/main/java/alfio/controller/api/admin/PollAdminApiController.java +++ b/src/main/java/alfio/controller/api/admin/PollAdminApiController.java @@ -23,7 +23,6 @@ import alfio.model.poll.PollStatistics; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.http.ResponseEntity; @@ -34,11 +33,14 @@ @RestController @RequestMapping("/admin/api/{eventName}/poll") -@RequiredArgsConstructor public class PollAdminApiController { private final PollManager pollManager; + public PollAdminApiController(PollManager pollManager) { + this.pollManager = pollManager; + } + @GetMapping ResponseEntity> getAllForEvent(@PathVariable("eventName") String eventName) { if(StringUtils.isEmpty(eventName)) { diff --git a/src/main/java/alfio/controller/api/admin/PromoCodeDiscountApiController.java b/src/main/java/alfio/controller/api/admin/PromoCodeDiscountApiController.java index 840c1f108f..23139d5ce0 100644 --- a/src/main/java/alfio/controller/api/admin/PromoCodeDiscountApiController.java +++ b/src/main/java/alfio/controller/api/admin/PromoCodeDiscountApiController.java @@ -17,49 +17,60 @@ package alfio.controller.api.admin; import alfio.manager.EventManager; +import alfio.manager.PromoCodeRequestManager; import alfio.model.PromoCodeDiscount; +import alfio.model.PromoCodeUsageResult; import alfio.model.modification.PromoCodeDiscountModification; import alfio.model.modification.PromoCodeDiscountWithFormattedTimeAndAmount; import alfio.repository.EventRepository; import alfio.repository.PromoCodeDiscountRepository; import alfio.util.ClockProvider; -import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.springframework.web.bind.annotation.*; +import java.security.Principal; import java.time.ZoneId; import java.time.ZoneOffset; -import java.time.ZonedDateTime; import java.util.List; -import java.util.Optional; - -import static alfio.model.PromoCodeDiscount.categoriesOrNull; @RestController @RequestMapping("/admin/api") -@RequiredArgsConstructor public class PromoCodeDiscountApiController { private final EventRepository eventRepository; - private final PromoCodeDiscountRepository promoCodeRepository; private final EventManager eventManager; - private final ClockProvider clockProvider; + private final PromoCodeRequestManager promoCodeRequestManager; + + public PromoCodeDiscountApiController(EventRepository eventRepository, + EventManager eventManager, + PromoCodeRequestManager promoCodeRequestManager) { + this.eventRepository = eventRepository; + this.eventManager = eventManager; + this.promoCodeRequestManager = promoCodeRequestManager; + } @PostMapping("/promo-code") public void addPromoCode(@RequestBody PromoCodeDiscountModification promoCode) { Integer eventId = promoCode.getEventId(); Integer organizationId = promoCode.getOrganizationId(); ZoneId zoneId = zoneIdFromEventId(eventId, promoCode.getUtcOffset()); - - int discount = promoCode.getDiscountValue(eventRepository.getEventCurrencyCode(eventId)); + + if(eventId != null && PromoCodeDiscount.supportsCurrencyCode(promoCode.getCodeType(), promoCode.getDiscountType())) { + String eventCurrencyCode = eventRepository.getEventCurrencyCode(eventId); + Validate.isTrue(eventCurrencyCode.equals(promoCode.getCurrencyCode()), "Currency code does not match"); + } + + int discount = promoCode.getDiscountValue(); eventManager.addPromoCode(promoCode.getPromoCode(), eventId, organizationId, promoCode.getStart().toZonedDateTime(zoneId), promoCode.getEnd().toZonedDateTime(zoneId), discount, promoCode.getDiscountType(), promoCode.getCategories(), promoCode.getMaxUsage(), - promoCode.getDescription(), promoCode.getEmailReference(), promoCode.getCodeType(), promoCode.getHiddenCategoryId()); + promoCode.getDescription(), promoCode.getEmailReference(), promoCode.getCodeType(), promoCode.getHiddenCategoryId(), promoCode.getCurrencyCode()); } @PostMapping("/promo-code/{promoCodeId}") public void updatePromoCode(@PathVariable("promoCodeId") int promoCodeId, @RequestBody PromoCodeDiscountModification promoCode) { - PromoCodeDiscount pcd = promoCodeRepository.findById(promoCodeId); + PromoCodeDiscount pcd = promoCodeRequestManager.findById(promoCodeId).orElseThrow(); ZoneId zoneId = zoneIdFromEventId(pcd.getEventId(), promoCode.getUtcOffset()); eventManager.updatePromoCode(promoCodeId, promoCode.getStart().toZonedDateTime(zoneId), promoCode.getEnd().toZonedDateTime(zoneId), promoCode.getMaxUsage(), promoCode.getCategories(), @@ -91,15 +102,22 @@ public void removePromoCode(@PathVariable("promoCodeId") int promoCodeId) { @PostMapping("/promo-code/{promoCodeId}/disable") public void disablePromoCode(@PathVariable("promoCodeId") int promoCodeId) { - promoCodeRepository.updateEventPromoCodeEnd(promoCodeId, ZonedDateTime.now(clockProvider.getClock())); + promoCodeRequestManager.disablePromoCode(promoCodeId); } @GetMapping("/promo-code/{promoCodeId}/count-use") public int countPromoCodeUse(@PathVariable("promoCodeId") int promoCodeId) { - Optional code = promoCodeRepository.findOptionalById(promoCodeId); - if(code.isEmpty()) { - return 0; + return promoCodeRequestManager.countUsage(promoCodeId); + } + + @GetMapping("/promo-code/{promoCodeId}/detailed-usage") + public List retrieveDetailedUsage(@PathVariable("promoCodeId") int promoCodeId, + @RequestParam(value = "eventShortName", required = false) String eventShortName, + Principal principal) { + Integer eventId = null; + if (StringUtils.isNotBlank(eventShortName)) { + eventId = eventManager.getEventAndOrganizationId(eventShortName, principal.getName()).getId(); } - return promoCodeRepository.countConfirmedPromoCode(promoCodeId, categoriesOrNull(code.get()), null, categoriesOrNull(code.get()) != null ? "X" : null); + return promoCodeRequestManager.retrieveDetailedUsage(promoCodeId, eventId); } } diff --git a/src/main/java/alfio/controller/api/admin/ResourceController.java b/src/main/java/alfio/controller/api/admin/ResourceController.java index 5446b263cc..b799234219 100644 --- a/src/main/java/alfio/controller/api/admin/ResourceController.java +++ b/src/main/java/alfio/controller/api/admin/ResourceController.java @@ -19,14 +19,14 @@ import alfio.controller.support.TemplateProcessor; import alfio.manager.ExtensionManager; import alfio.manager.FileUploadManager; +import alfio.manager.SubscriptionManager; import alfio.manager.UploadedResourceManager; import alfio.manager.i18n.MessageSourceManager; import alfio.manager.user.UserManager; -import alfio.model.ContentLanguage; -import alfio.model.Event; -import alfio.model.PriceContainer; -import alfio.model.UploadedResource; +import alfio.model.*; import alfio.model.modification.UploadBase64FileModification; +import alfio.model.subscription.SubscriptionDescriptor; +import alfio.model.transaction.PaymentProxy; import alfio.model.user.Organization; import alfio.repository.EventRepository; import alfio.repository.user.OrganizationRepository; @@ -35,9 +35,9 @@ import alfio.util.TemplateManager; import alfio.util.TemplateResource; import com.samskivert.mustache.MustacheException; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -55,20 +55,18 @@ import java.security.Principal; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; +import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @RestController @RequestMapping("/admin/api") -@Log4j2 -@AllArgsConstructor public class ResourceController { + private static final Logger log = LoggerFactory.getLogger(ResourceController.class); + private static final String TIMEZONE = "Europe/Zurich"; private final UploadedResourceManager uploadedResourceManager; private final UserManager userManager; private final EventRepository eventRepository; @@ -78,6 +76,29 @@ public class ResourceController { private final FileUploadManager fileUploadManager; private final ExtensionManager extensionManager; private final ClockProvider clockProvider; + private final SubscriptionManager subscriptionManager; + + public ResourceController(UploadedResourceManager uploadedResourceManager, + UserManager userManager, + EventRepository eventRepository, + MessageSourceManager messageSourceManager, + TemplateManager templateManager, + OrganizationRepository organizationRepository, + FileUploadManager fileUploadManager, + ExtensionManager extensionManager, + ClockProvider clockProvider, + SubscriptionManager subscriptionManager) { + this.uploadedResourceManager = uploadedResourceManager; + this.userManager = userManager; + this.eventRepository = eventRepository; + this.messageSourceManager = messageSourceManager; + this.templateManager = templateManager; + this.organizationRepository = organizationRepository; + this.fileUploadManager = fileUploadManager; + this.extensionManager = extensionManager; + this.clockProvider = clockProvider; + this.subscriptionManager = subscriptionManager; + } @ExceptionHandler(Exception.class) @@ -112,6 +133,7 @@ public void getTemplate(@PathVariable("name") TemplateResource name, @PathVariab public void previewTemplate(@PathVariable("name") TemplateResource name, @PathVariable("locale") String locale, @RequestParam(required = false, value = "organizationId") Integer organizationId, @RequestParam(required = false, value = "eventId") Integer eventId, + @RequestParam(required = false, value = "subscriptionDescriptorId") UUID subscriptionDescriptorId, @RequestBody UploadBase64FileModification template, Principal principal, HttpServletResponse response) throws IOException { @@ -120,23 +142,12 @@ public void previewTemplate(@PathVariable("name") TemplateResource name, @PathVa Locale loc = LocaleUtil.forLanguageTag(locale); if (organizationId != null) { - Event event; - if (eventId!= null) { - checkAccess(organizationId, eventId, principal); - event = eventRepository.findById(eventId); - } else { - checkAccess(organizationId, principal); - var zoneId = ZoneId.of("Europe/Zurich"); - event = new Event(-1, Event.EventFormat.IN_PERSON, "TEST", "TEST", "TEST", "0", "0", ZonedDateTime.now(clockProvider.withZone(zoneId)), - ZonedDateTime.now(clockProvider.withZone(zoneId)), "Europe/Zurich", "http://localhost", "http://localhost", null, - "http://localhost", null, null, "CHF", BigDecimal.TEN, null, "42", organizationId, - ContentLanguage.ALL_LANGUAGES_IDENTIFIER, 0, PriceContainer.VatStatus.NONE, "1", Event.Status.PUBLIC); - } + PurchaseContext purchaseContext = getPurchaseContext(organizationId, eventId, subscriptionDescriptorId, principal, name); Organization organization = organizationRepository.getById(organizationId); - Optional image = TemplateProcessor.extractImageModel(event, fileUploadManager); - Map model = name.prepareSampleModel(organization, event, image); - String renderedTemplate = templateManager.renderString(event, template.getFileAsString(), model, loc, name.getTemplateOutput()); + Optional image = TemplateProcessor.extractImageModel(purchaseContext, fileUploadManager); + Map model = name.prepareSampleModel(organization, purchaseContext, image); + String renderedTemplate = templateManager.renderString(purchaseContext, template.getFileAsString(), model, loc, name.getTemplateOutput()); if(MediaType.TEXT_PLAIN_VALUE.equals(name.getRenderedContentType()) || TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE.equals(name.getRenderedContentType())) { response.addHeader("Content-Disposition", "attachment; filename="+name.name()+".txt"); response.setContentType(MediaType.TEXT_PLAIN_VALUE); @@ -148,7 +159,7 @@ public void previewTemplate(@PathVariable("name") TemplateResource name, @PathVa try (OutputStream os = response.getOutputStream()) { response.setContentType(MediaType.APPLICATION_PDF_VALUE); response.addHeader("Content-Disposition", "attachment; filename="+name.name()+".pdf"); - TemplateProcessor.renderToPdf(renderedTemplate, os, extensionManager, event); + TemplateProcessor.renderToPdf(renderedTemplate, os, extensionManager, purchaseContext); } } else { throw new IllegalStateException("cannot enter here!"); @@ -156,6 +167,79 @@ public void previewTemplate(@PathVariable("name") TemplateResource name, @PathVa } } + private PurchaseContext getPurchaseContext(int organizationId, + Integer eventId, + UUID subscriptionDescriptorId, + Principal principal, + TemplateResource templateResource) { + if (templateResource.getPurchaseContextType() == PurchaseContext.PurchaseContextType.event) { + return getEvent(organizationId, eventId, principal); + } + return getSubscriptionDescriptor(organizationId, subscriptionDescriptorId, principal); + } + + private SubscriptionDescriptor getSubscriptionDescriptor(int organizationId, UUID subscriptionDescriptorId, Principal principal) { + if (subscriptionDescriptorId != null) { + return subscriptionManager.getSubscriptionById(subscriptionDescriptorId).orElseThrow(); + } + + Function> contentProducer = prefix -> ContentLanguage.ALL_LANGUAGES.stream() + .map(cl -> Map.entry(cl.getLanguage(), cl.getDisplayLanguage() + " " + prefix)) + .reduce(new HashMap(), (map, entry) -> { + map.put(entry.getKey(), entry.getValue()); + return map; + }, (map1, map2) -> { + map1.putAll(map2); + return map1; + }); + checkAccess(organizationId, principal); + var zoneId = ZoneId.of(TIMEZONE); + return new SubscriptionDescriptor(UUID.randomUUID(), + contentProducer.apply("title"), + contentProducer.apply("description"), + -1, + ZonedDateTime.now(clockProvider.withZone(zoneId)), + ZonedDateTime.now(clockProvider.withZone(zoneId)), + ZonedDateTime.now(clockProvider.withZone(zoneId)).plusDays(1), + 100, + new BigDecimal("7.7"), + PriceContainer.VatStatus.INCLUDED, + "CHF", + true, + organizationId, + 1, + SubscriptionDescriptor.SubscriptionValidityType.NOT_SET, + null, + -1, + ZonedDateTime.now(clockProvider.withZone(zoneId)), + ZonedDateTime.now(clockProvider.withZone(zoneId)).plusDays(1), + SubscriptionDescriptor.SubscriptionUsageType.ONCE_PER_EVENT, + "https://alf.io", + "https://alf.io", + null, + List.of(PaymentProxy.STRIPE.name()), + "42", + TIMEZONE, + true + ); + } + + private Event getEvent(Integer organizationId, Integer eventId, Principal principal) { + Event event; + if (eventId != null) { + checkAccess(organizationId, eventId, principal); + event = eventRepository.findById(eventId); + } else { + checkAccess(organizationId, principal); + var zoneId = ZoneId.of(TIMEZONE); + event = new Event(-1, Event.EventFormat.IN_PERSON, "TEST", "TEST", "TEST", "0", "0", ZonedDateTime.now(clockProvider.withZone(zoneId)), + ZonedDateTime.now(clockProvider.withZone(zoneId)), TIMEZONE, "http://localhost", "http://localhost", null, + "http://localhost", null, null, "CHF", BigDecimal.TEN, null, "42", organizationId, + ContentLanguage.ALL_LANGUAGES_IDENTIFIER, 0, PriceContainer.VatStatus.NONE, "1", Event.Status.PUBLIC); + } + return event; + } + //------------------ diff --git a/src/main/java/alfio/controller/api/admin/SerializablePair.java b/src/main/java/alfio/controller/api/admin/SerializablePair.java index 15d8a52d77..bbc7a19901 100644 --- a/src/main/java/alfio/controller/api/admin/SerializablePair.java +++ b/src/main/java/alfio/controller/api/admin/SerializablePair.java @@ -16,11 +16,13 @@ */ package alfio.controller.api.admin; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.experimental.Delegate; import org.apache.commons.lang3.tuple.Pair; public final class SerializablePair { @Delegate + @JsonIgnore private final Pair pair; private SerializablePair(Pair pair) { diff --git a/src/main/java/alfio/controller/api/admin/SpecialPriceApiController.java b/src/main/java/alfio/controller/api/admin/SpecialPriceApiController.java index 397e31b8dc..32744f04e7 100644 --- a/src/main/java/alfio/controller/api/admin/SpecialPriceApiController.java +++ b/src/main/java/alfio/controller/api/admin/SpecialPriceApiController.java @@ -22,9 +22,10 @@ import alfio.model.modification.UploadBase64FileModification; import com.opencsv.CSVReader; import com.opencsv.exceptions.CsvException; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -42,9 +43,10 @@ @RestController @RequestMapping("/admin/api") -@Log4j2 public class SpecialPriceApiController { + private static final Logger log = LoggerFactory.getLogger(SpecialPriceApiController.class); + private final SpecialPriceManager specialPriceManager; @Autowired diff --git a/src/main/java/alfio/controller/api/admin/SubscriptionApiController.java b/src/main/java/alfio/controller/api/admin/SubscriptionApiController.java index 6268ee155a..785c3a25bf 100644 --- a/src/main/java/alfio/controller/api/admin/SubscriptionApiController.java +++ b/src/main/java/alfio/controller/api/admin/SubscriptionApiController.java @@ -29,6 +29,7 @@ import java.security.Principal; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; @RestController @RequestMapping("/admin/api/organization/{organizationId}/subscription") @@ -37,7 +38,8 @@ public class SubscriptionApiController { private final SubscriptionManager subscriptionManager; private final UserManager userManager; - public SubscriptionApiController(SubscriptionManager subscriptionManager, UserManager userManager) { + public SubscriptionApiController(SubscriptionManager subscriptionManager, + UserManager userManager) { this.subscriptionManager = subscriptionManager; this.userManager = userManager; } @@ -75,10 +77,17 @@ ResponseEntity getSingle(@PathVariable("orga ResponseEntity create(@PathVariable("organizationId") int organizationId, @RequestBody SubscriptionDescriptorModification subscriptionDescriptor, Principal principal) { - if (organizationId == subscriptionDescriptor.getOrganizationId() && userManager.isOwnerOfOrganization(principal.getName(), subscriptionDescriptor.getOrganizationId())) { + + if (organizationId != subscriptionDescriptor.getOrganizationId() + || !userManager.isOwnerOfOrganization(principal.getName(), subscriptionDescriptor.getOrganizationId())) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + var result = SubscriptionDescriptorModification.validate(subscriptionDescriptor); + if (result.isSuccess()) { return ResponseEntity.of(subscriptionManager.createSubscriptionDescriptor(subscriptionDescriptor)); } else { - return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + return ResponseEntity.badRequest().build(); } } @@ -119,4 +128,43 @@ ResponseEntity> getLinkedEvents(@PathVariable("organ return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } } + + /** + * Deactivates a subscription descriptor and removes the link with events, if any. + * + * This will ensure that existing reservations made or ticket registered using this subscription won't have + * to be deleted. + * + * @param organizationId + * @param descriptorId + * @param principal + * @return + */ + @DeleteMapping("/{subscriptionId}") + ResponseEntity deactivate(@PathVariable("organizationId") int organizationId, + @PathVariable("subscriptionId") UUID descriptorId, + Principal principal) { + if(userManager.isOwnerOfOrganization(principal.getName(), organizationId)) { + return deactivateSubscriptionDescriptor(organizationId, descriptorId, subscriptionManager); + } + + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + + public static ResponseEntity deactivateSubscriptionDescriptor(int organizationId, + UUID descriptorId, + SubscriptionManager subscriptionManager) { + var result = subscriptionManager.deactivateDescriptor(organizationId, descriptorId); + if (result.isSuccess()) { + return ResponseEntity.ok().build(); + } else { + return ResponseEntity.badRequest().build(); + } + } + + public static List loadLinkedEvents(List eventSubscriptionLinks) { + return eventSubscriptionLinks.stream() + .map(EventSubscriptionLink::getEventShortName) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/alfio/controller/api/admin/SystemApiKeyApiController.java b/src/main/java/alfio/controller/api/admin/SystemApiKeyApiController.java new file mode 100644 index 0000000000..428235e303 --- /dev/null +++ b/src/main/java/alfio/controller/api/admin/SystemApiKeyApiController.java @@ -0,0 +1,58 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.admin; + +import alfio.manager.system.ConfigurationManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin/api/system/api-key") +public class SystemApiKeyApiController { + private static final Logger log = LoggerFactory.getLogger(SystemApiKeyApiController.class); + private final ConfigurationManager configurationManager; + + public SystemApiKeyApiController(ConfigurationManager configurationManager) { + this.configurationManager = configurationManager; + } + + @GetMapping() + public ResponseEntity retrieveApiKey() { + try { + return ResponseEntity.ok(configurationManager.retrieveSystemApiKey(false)); + } catch(RuntimeException e) { + log.error("Error while retrieving system API Key", e); + return ResponseEntity.internalServerError().build(); + } + } + + @PutMapping() + public ResponseEntity rotateApiKey() { + try { + return ResponseEntity.ok(configurationManager.retrieveSystemApiKey(true)); + } catch(RuntimeException e) { + log.error("Error while rotating system API Key", e); + return ResponseEntity.internalServerError().build(); + } + } + +} diff --git a/src/main/java/alfio/controller/api/admin/UsersApiController.java b/src/main/java/alfio/controller/api/admin/UsersApiController.java index aee06ceb59..1de27f4c28 100644 --- a/src/main/java/alfio/controller/api/admin/UsersApiController.java +++ b/src/main/java/alfio/controller/api/admin/UsersApiController.java @@ -16,7 +16,7 @@ */ package alfio.controller.api.admin; -import alfio.config.authentication.AuthenticationConstants; +import alfio.config.authentication.support.AuthenticationConstants; import alfio.manager.system.ConfigurationManager; import alfio.manager.user.UserManager; import alfio.model.modification.OrganizationModification; @@ -28,15 +28,14 @@ import alfio.util.Json; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.*; @@ -55,14 +54,19 @@ @RestController @RequestMapping("/admin/api") -@Log4j2 -@AllArgsConstructor public class UsersApiController { + private static final Logger log = LoggerFactory.getLogger(UsersApiController.class); + private static final String OK = "OK"; private final UserManager userManager; private final ConfigurationManager configurationManager; + public UsersApiController(UserManager userManager, ConfigurationManager configurationManager) { + this.userManager = userManager; + this.configurationManager = configurationManager; + } + @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody @@ -78,19 +82,23 @@ public Collection getAllRoles(Principal principal) { /** * This endpoint is intended only for external use. If a user is registered as "sponsor", then the answer will be "SPONSOR", otherwise "OPERATOR". - * @return "SPONSOR" or "OPERATOR", depending on current user's privileges. + * @return "SPONSOR", "SUPERVISOR", or "OPERATOR", depending on current user's privileges. */ @GetMapping("/user-type") public String getLoggedUserType() { - return SecurityContextHolder.getContext() + var authorities = SecurityContextHolder.getContext() .getAuthentication() .getAuthorities() .stream() - .map(GrantedAuthority::getAuthority) - .map(s -> StringUtils.substringAfter(s, "ROLE_")) - .filter(AuthenticationConstants.SPONSOR::equals) - .findFirst() - .orElse(AuthenticationConstants.OPERATOR); + .map(ga -> StringUtils.substringAfter(ga.getAuthority(), "ROLE_")) + .collect(Collectors.toSet()); + if (authorities.contains(AuthenticationConstants.SPONSOR)) { + return AuthenticationConstants.SPONSOR; + } else if (authorities.contains(AuthenticationConstants.SUPERVISOR)) { + return AuthenticationConstants.SUPERVISOR; + } else { + return AuthenticationConstants.OPERATOR; + } } @GetMapping("/user/details") @@ -129,15 +137,15 @@ public ResponseEntity bulkCreate(@RequestBody BulkApiKeyCreation request Optional userOptional = userManager.findOptionalEnabledUserByUsername(principal.getName()) .filter(u -> userManager.isOwnerOfOrganization(u, request.organizationId)); if(userOptional.isPresent()) { - userManager.bulkInsertApiKeys(request.organizationId, request.role, request.descriptions); + userManager.bulkInsertApiKeys(request.organizationId, request.role, request.descriptions, principal); return ResponseEntity.ok("OK"); } return ResponseEntity.badRequest().build(); } @PostMapping("/organizations/new") - public String insertOrganization(@RequestBody OrganizationModification om) { - userManager.createOrganization(om); + public String insertOrganization(@RequestBody OrganizationModification om, Principal principal) { + userManager.createOrganization(om, principal); return OK; } @@ -172,7 +180,7 @@ public String editUser(@RequestBody UserModification userModification, Principal userManager.editUser(userModification.getId(), userModification.getOrganizationId(), userModification.getUsername(), userModification.getFirstName(), userModification.getLastName(), userModification.getEmailAddress(), userModification.getDescription(), - Role.valueOf(userModification.getRole()), principal.getName()); + Role.valueOf(userModification.getRole()), principal); return OK; } @@ -185,7 +193,7 @@ public UserWithPasswordAndQRCode insertUser(@RequestBody UserModification userMo userModification.getFirstName(), userModification.getLastName(), userModification.getEmailAddress(), requested, type == null ? User.Type.INTERNAL : type, - userModification.getValidToAsDateTime(), userModification.getDescription()); + userModification.getValidToAsDateTime(), userModification.getDescription(), principal); String qrCode = type != User.Type.API_KEY ? Base64.getEncoder().encodeToString(generateQRCode(userWithPassword, baseUrl)) : null; return new UserWithPasswordAndQRCode(userWithPassword, qrCode); } @@ -228,19 +236,19 @@ private static byte[] generateQRCode(UserWithPassword userWithPassword, String b @DeleteMapping("/users/{id}") public String deleteUser(@PathVariable("id") int userId, Principal principal) { - userManager.deleteUser(userId, principal.getName()); + userManager.deleteUser(userId, principal); return OK; } @PostMapping("/users/{id}/enable/{enable}") public String enableUser(@PathVariable("id") int userId, @PathVariable("enable")boolean enable, Principal principal) { - userManager.enable(userId, principal.getName(), enable); + userManager.enable(userId, enable, principal); return OK; } @GetMapping("/users/{id}") - public UserModification loadUser(@PathVariable("id") int userId) { - User user = userManager.findUser(userId); + public UserModification loadUser(@PathVariable("id") int userId, Principal principal) { + User user = userManager.findUser(userId, principal); List userOrganizations = userManager.findUserOrganizations(user.getUsername()); return new UserModification(user.getId(), userOrganizations.get(0).getId(), userManager.getUserRole(user).name(), user.getUsername(), user.getFirstName(), user.getLastName(), user.getEmailAddress(), @@ -259,19 +267,18 @@ public UserModification loadCurrentUser(Principal principal) { @PostMapping("/users/current/update-password") public ValidationResult updateCurrentUserPassword(@RequestBody PasswordModification passwordModification, Principal principal) { return userManager.validateNewPassword(principal.getName(), passwordModification.oldPassword, passwordModification.newPassword, passwordModification.newPasswordConfirm) - .ifSuccess(() -> userManager.updatePassword(principal.getName(), passwordModification.newPassword)); + .ifSuccess(() -> userManager.updateCurrentUserPassword(passwordModification.newPassword, principal)); } @PostMapping("/users/current/edit") public void updateCurrentUser(@RequestBody UserModification userModification, Principal principal) { - User user = userManager.findUserByUsername(principal.getName()); - userManager.updateUserContactInfo(user.getId(), userModification.getFirstName(), userModification.getLastName(), userModification.getEmailAddress()); + userManager.updateCurrentUserContactInfo(userModification.getFirstName(), userModification.getLastName(), userModification.getEmailAddress(), principal); } @PutMapping("/users/{id}/reset-password") - public UserWithPasswordAndQRCode resetPassword(@PathVariable("id") int userId, @RequestParam("baseUrl") String baseUrl) { - UserWithPassword userWithPassword = userManager.resetPassword(userId); + public UserWithPasswordAndQRCode resetPassword(@PathVariable("id") int userId, @RequestParam("baseUrl") String baseUrl, Principal principal) { + UserWithPassword userWithPassword = userManager.resetPassword(userId, principal); return new UserWithPasswordAndQRCode(userWithPassword, Base64.getEncoder().encodeToString(generateQRCode(userWithPassword, baseUrl))); } @@ -301,7 +308,7 @@ public String getDescription() { return role.getDescription(); } - public String getTarget() { return role.getTarget().name(); } + public List getTarget() { return role.getTarget().stream().map(RoleTarget::name).collect(Collectors.toList()); } } private static final class PasswordModification { diff --git a/src/main/java/alfio/controller/api/admin/UtilsApiController.java b/src/main/java/alfio/controller/api/admin/UtilsApiController.java index 6a5dea5f2e..ef442b8fdb 100644 --- a/src/main/java/alfio/controller/api/admin/UtilsApiController.java +++ b/src/main/java/alfio/controller/api/admin/UtilsApiController.java @@ -22,9 +22,10 @@ import alfio.manager.EventNameManager; import alfio.util.MustacheCustomTag; import alfio.util.Wrappers; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; import org.joda.money.CurrencyUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; @@ -41,10 +42,11 @@ @RestController @RequestMapping("/admin/api/utils") -@Log4j2 public class UtilsApiController { - private static final List CURRENCIES_BLACKLIST = Arrays.asList("USN", "USS", "CHE", "CHW"); + private static final Logger log = LoggerFactory.getLogger(UtilsApiController.class); + + private static final Set CURRENCIES_BLOCKLIST = Set.of("USN", "USS", "CHE", "CHW"); private final EventNameManager eventNameManager; private final String version; private final Environment environment; @@ -94,9 +96,9 @@ public Map getApplicationInfo(Principal principal) { public List getCurrencies() { return CurrencyUnit.registeredCurrencies().stream() //we don't support pseudo currencies, as it is very unlikely that payment providers would support them - .filter(c -> !c.isPseudoCurrency() && !CURRENCIES_BLACKLIST.contains(c.getCode()) && Wrappers.optionally(() -> Currency.getInstance(c.getCode())).isPresent()) + .filter(c -> !c.isPseudoCurrency() && !CURRENCIES_BLOCKLIST.contains(c.getCode()) && Wrappers.optionally(() -> Currency.getInstance(c.getCode())).isPresent()) .map(c -> new CurrencyDescriptor(c.getCode(), c.toCurrency().getDisplayName(Locale.ENGLISH), c.getSymbol(Locale.ENGLISH), c.getDecimalPlaces())) - .collect(Collectors.toList()); + .toList(); } @GetMapping("/countriesForVat") diff --git a/src/main/java/alfio/controller/api/pass/PassKitApiController.java b/src/main/java/alfio/controller/api/pass/PassKitApiController.java index fb088fa90f..25c4fa05ef 100644 --- a/src/main/java/alfio/controller/api/pass/PassKitApiController.java +++ b/src/main/java/alfio/controller/api/pass/PassKitApiController.java @@ -19,9 +19,9 @@ import alfio.manager.PassKitManager; import alfio.model.EventAndOrganizationId; import alfio.model.Ticket; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -34,12 +34,16 @@ */ @RestController @RequestMapping("/api/pass/event/{eventName}/v1") -@Log4j2 -@RequiredArgsConstructor public class PassKitApiController { + private static final Logger log = LoggerFactory.getLogger(PassKitApiController.class); + private final PassKitManager passKitManager; + public PassKitApiController(PassKitManager passKitManager) { + this.passKitManager = passKitManager; + } + @GetMapping("/version/passes/{passTypeIdentifier}/{serialNumber}") public void getLatestVersion(@PathVariable("eventName") String eventName, @@ -52,13 +56,36 @@ public void getLatestVersion(@PathVariable("eventName") String eventName, response.sendError(HttpServletResponse.SC_NOT_FOUND); } else { Pair pair = validationResult.get(); - try (var os = response.getOutputStream()) { - response.setContentType("application/vnd.apple.pkpass"); - passKitManager.writePass(pair.getRight(), pair.getLeft(), os); - } catch (Exception e) { - log.warn("Error during pass generation", e); - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + writePassResponse(response, pair.getLeft(), pair.getRight(), false); + } + } + + @GetMapping("/version/passes/{ticketUuid}") + public void downloadPassForTicket(@PathVariable("eventName") String eventName, + @PathVariable("ticketUuid") String ticketUuid, + HttpServletResponse response) throws IOException { + var ticketAndEventData = passKitManager.retrieveTicketDetails(eventName, ticketUuid); + if (ticketAndEventData.isPresent()) { + var pair = ticketAndEventData.get(); + writePassResponse(response, pair.getKey(), pair.getValue(), true); + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + } + } + + private void writePassResponse(HttpServletResponse response, + EventAndOrganizationId eventAndOrganizationId, + Ticket ticket, + boolean addFilename) throws IOException { + try (var os = response.getOutputStream()) { + response.setContentType("application/vnd.apple.pkpass"); + if (addFilename) { + response.setHeader("Content-Disposition", "attachment; filename=Passbook-"+ticket.getUuid().substring(0, 8)+".pkpass"); } + passKitManager.writePass(ticket, eventAndOrganizationId, os); + } catch (Exception e) { + log.warn("Error during pass generation", e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } diff --git a/src/main/java/alfio/controller/api/support/AdditionalField.java b/src/main/java/alfio/controller/api/support/AdditionalField.java new file mode 100644 index 0000000000..a8e4b46de2 --- /dev/null +++ b/src/main/java/alfio/controller/api/support/AdditionalField.java @@ -0,0 +1,34 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.support; + +import java.util.List; +import java.util.Map; + + +public record AdditionalField(String name, + String value, + String type, + boolean required, + boolean editable, + Integer minLength, + Integer maxLength, + List restrictedValues, + List fields, + boolean beforeStandardFields, + Map description) { +} diff --git a/src/main/java/alfio/controller/api/support/BookingInfoTicket.java b/src/main/java/alfio/controller/api/support/BookingInfoTicket.java new file mode 100644 index 0000000000..c18db9af69 --- /dev/null +++ b/src/main/java/alfio/controller/api/support/BookingInfoTicket.java @@ -0,0 +1,135 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.support; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class BookingInfoTicket { + private final String uuid; + private final String firstName; + private final String lastName; + private final String email; + private final String fullName; + private final String userLanguage; + private final boolean assigned; + private final boolean locked; + private final boolean acquired; + private final boolean cancellationEnabled; + private final boolean sendMailEnabled; + private final boolean downloadEnabled; + private final List ticketFieldConfiguration; + private final Map formattedOnlineCheckInDate; + private final boolean onlineEventStarted; + + public BookingInfoTicket(String uuid, + String firstName, + String lastName, + String email, + String fullName, + String userLanguage, + boolean assigned, + boolean locked, + boolean acquired, + boolean cancellationEnabled, + boolean sendMailEnabled, + boolean downloadEnabled, + List ticketFieldConfiguration, + Map formattedOnlineCheckInDate, + boolean onlineEventStarted) { + this.uuid = uuid; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.fullName = fullName; + this.userLanguage = userLanguage; + this.assigned = assigned; + this.locked = locked; + this.acquired = acquired; + this.cancellationEnabled = cancellationEnabled; + this.sendMailEnabled = sendMailEnabled; + this.downloadEnabled = downloadEnabled; + this.ticketFieldConfiguration = ticketFieldConfiguration; + this.formattedOnlineCheckInDate = formattedOnlineCheckInDate; + this.onlineEventStarted = onlineEventStarted; + } + + public String getEmail() { + return email; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getUuid() { + return uuid; + } + + public String getFullName() { + return fullName; + } + + public boolean isAssigned() { + return assigned; + } + + public boolean isAcquired() { + return acquired; + } + + public String getUserLanguage() { + return userLanguage; + } + + public boolean isLocked() { + return locked; + } + + public boolean isCancellationEnabled() { + return cancellationEnabled; + } + + public List getTicketFieldConfigurationBeforeStandard() { + return ticketFieldConfiguration.stream().filter(AdditionalField::beforeStandardFields).collect(Collectors.toList()); + } + + public List getTicketFieldConfigurationAfterStandard() { + return ticketFieldConfiguration.stream().filter(tv -> !tv.beforeStandardFields()).collect(Collectors.toList()); + } + + public Map getFormattedOnlineCheckInDate() { + return formattedOnlineCheckInDate; + } + + public boolean isOnlineEventStarted() { + return onlineEventStarted; + } + + public boolean isSendMailEnabled() { + return sendMailEnabled; + } + + public boolean isDownloadEnabled() { + return downloadEnabled; + } +} diff --git a/src/main/java/alfio/controller/api/v2/user/support/BookingInfoTicketLoader.java b/src/main/java/alfio/controller/api/support/BookingInfoTicketLoader.java similarity index 66% rename from src/main/java/alfio/controller/api/v2/user/support/BookingInfoTicketLoader.java rename to src/main/java/alfio/controller/api/support/BookingInfoTicketLoader.java index e2073c8c73..8222e18bba 100644 --- a/src/main/java/alfio/controller/api/v2/user/support/BookingInfoTicketLoader.java +++ b/src/main/java/alfio/controller/api/support/BookingInfoTicketLoader.java @@ -14,10 +14,8 @@ * You should have received a copy of the GNU General Public License * along with alf.io. If not, see . */ -package alfio.controller.api.v2.user.support; +package alfio.controller.api.support; -import alfio.controller.api.support.TicketHelper; -import alfio.controller.api.v2.model.ReservationInfo; import alfio.controller.support.Formatters; import alfio.manager.EventManager; import alfio.manager.TicketReservationManager; @@ -30,7 +28,6 @@ import alfio.util.ClockProvider; import alfio.util.EventUtil; import alfio.util.Validator; -import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import java.util.*; @@ -40,7 +37,6 @@ import static alfio.model.system.ConfigurationKeys.*; @Component -@AllArgsConstructor public class BookingInfoTicketLoader { private final EventManager eventManager; @@ -52,8 +48,26 @@ public class BookingInfoTicketLoader { private final MessageSourceManager messageSourceManager; private final ClockProvider clockProvider; + public BookingInfoTicketLoader(EventManager eventManager, + ConfigurationManager configurationManager, + TicketFieldRepository ticketFieldRepository, + TicketHelper ticketHelper, + AdditionalServiceItemRepository additionalServiceItemRepository, + TicketReservationManager ticketReservationManager, + MessageSourceManager messageSourceManager, + ClockProvider clockProvider) { + this.eventManager = eventManager; + this.configurationManager = configurationManager; + this.ticketFieldRepository = ticketFieldRepository; + this.ticketHelper = ticketHelper; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.ticketReservationManager = ticketReservationManager; + this.messageSourceManager = messageSourceManager; + this.clockProvider = clockProvider; + } + - public ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket ticket, Event event) { + public BookingInfoTicket toBookingInfoTicket(Ticket ticket, Event event) { var descriptionsByTicketFieldId = ticketFieldRepository.findDescriptions(event.getShortName()) .stream() .collect(Collectors.groupingBy(TicketFieldDescription::getTicketFieldConfigurationId)); @@ -69,7 +83,7 @@ public ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket ticket, Even var eventConfiguration = eventManager.getMetadataForEvent(event).getOnlineConfiguration(); var ticketCategoryConfiguration = eventManager.getMetadataForCategory(event, ticket.getCategoryId()).getOnlineConfiguration(); var checkInDate = EventUtil.firstMatchingCallLink(event.getZoneId(), ticketCategoryConfiguration, eventConfiguration) - .map(link -> link.getValidFrom().atZone(event.getZoneId())) + .map(link -> link.validFrom().atZone(event.getZoneId())) .orElse(event.getBegin()); formattedDates = Formatters.getFormattedDate(event, checkInDate, "common.ticket-category.date-format", messageSourceManager.getMessageSourceFor(event)); @@ -86,17 +100,18 @@ public ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket ticket, Even onlineEventStarted); } - public ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket t, - boolean hasPaidSupplement, - Event event, - Validator.TicketFieldsFilterer ticketFieldsFilterer, - Map> descriptionsByTicketFieldId, - Map> valuesByTicketIds, - Map formattedOnlineCheckInDate, - boolean onlineEventStarted) { + public BookingInfoTicket toBookingInfoTicket(Ticket t, + boolean hasPaidSupplement, + Event event, + Validator.TicketFieldsFilterer ticketFieldsFilterer, + Map> descriptionsByTicketFieldId, + Map> valuesByTicketIds, + Map formattedOnlineCheckInDate, + boolean onlineEventStarted) { // TODO: n+1, should be cleaned up! see TicketDecorator.getCancellationEnabled var configuration = configurationManager.getFor(EnumSet.of(ALLOW_FREE_TICKETS_CANCELLATION, SEND_TICKETS_AUTOMATICALLY, ALLOW_TICKET_DOWNLOAD), ConfigurationLevel.ticketCategory(event, t.getCategoryId())); boolean cancellationEnabled = t.getFinalPriceCts() == 0 && + !event.expired() && (!hasPaidSupplement && configuration.get(ALLOW_FREE_TICKETS_CANCELLATION).getValueAsBooleanOrDefault()) && // freeCancellationEnabled eventManager.checkTicketCancellationPrerequisites().apply(t); // cancellationPrerequisitesMet // @@ -118,15 +133,15 @@ public Validator.TicketFieldsFilterer getTicketFieldsFilterer(String reservation ticketReservationManager.findFirstInReservation(reservationId)); } - private static ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket ticket, - boolean cancellationEnabled, - boolean sendMailEnabled, - boolean downloadEnabled, - List ticketFields, - Map> descriptionsByTicketFieldId, - List ticketFieldValues, - Map formattedOnlineCheckInDate, - boolean onlineEventStarted) { + private static BookingInfoTicket toBookingInfoTicket(Ticket ticket, + boolean cancellationEnabled, + boolean sendMailEnabled, + boolean downloadEnabled, + List ticketFields, + Map> descriptionsByTicketFieldId, + List ticketFieldValues, + Map formattedOnlineCheckInDate, + boolean onlineEventStarted) { var valueById = ticketFieldValues.stream().collect(Collectors.toMap(TicketFieldValue::getTicketFieldConfigurationId, Function.identity())); @@ -142,7 +157,7 @@ private static ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket tick return toAdditionalField(t, descs); }).collect(Collectors.toList()); - return new ReservationInfo.BookingInfoTicket(ticket.getUuid(), + return new BookingInfoTicket(ticket.getUuid(), ticket.getFirstName(), ticket.getLastName(), ticket.getEmail(), @@ -159,15 +174,15 @@ private static ReservationInfo.BookingInfoTicket toBookingInfoTicket(Ticket tick onlineEventStarted); } - private static ReservationInfo.AdditionalField toAdditionalField(TicketFieldConfigurationDescriptionAndValue t, Map description) { - var fields = t.getFields().stream().map(f -> new ReservationInfo.Field(f.getFieldIndex(), f.getFieldValue())).collect(Collectors.toList()); - return new ReservationInfo.AdditionalField(t.getName(), t.getValue(), t.getType(), t.isRequired(), t.isEditable(), + private static AdditionalField toAdditionalField(TicketFieldConfigurationDescriptionAndValue t, Map description) { + var fields = t.getFields().stream().map(f -> new Field(f.getFieldIndex(), f.getFieldValue())).collect(Collectors.toList()); + return new AdditionalField(t.getName(), t.getValue(), t.getType(), t.isRequired(), t.isEditable(), t.getMinLength(), t.getMaxLength(), t.getRestrictedValues(), fields, t.isBeforeStandardFields(), description); } - private static Map fromFieldDescriptions(List descs) { + private static Map fromFieldDescriptions(List descs) { return descs.stream().collect(Collectors.toMap(TicketFieldDescription::getLocale, - d -> new ReservationInfo.Description(d.getLabelDescription(), d.getPlaceholderDescription(), d.getRestrictedValuesDescription()))); + d -> new Description(d.getLabelDescription(), d.getPlaceholderDescription(), d.getRestrictedValuesDescription()))); } } diff --git a/src/main/java/alfio/controller/api/support/CspReportApiController.java b/src/main/java/alfio/controller/api/support/CspReportApiController.java index eb629c1061..4bdfb037f0 100644 --- a/src/main/java/alfio/controller/api/support/CspReportApiController.java +++ b/src/main/java/alfio/controller/api/support/CspReportApiController.java @@ -18,8 +18,8 @@ import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @@ -33,13 +33,17 @@ @RestController -@Log4j2 -@AllArgsConstructor public class CspReportApiController { + private static final Logger log = LoggerFactory.getLogger(CspReportApiController.class); + private final ConfigurationManager configurationManager; + public CspReportApiController(ConfigurationManager configurationManager) { + this.configurationManager = configurationManager; + } + @PostMapping("/report-csp-violation") public boolean logCspViolation(HttpServletRequest request) throws IOException { diff --git a/src/main/java/alfio/controller/api/support/CurrencyDescriptor.java b/src/main/java/alfio/controller/api/support/CurrencyDescriptor.java index 4cc44b2afe..579a6b5e62 100644 --- a/src/main/java/alfio/controller/api/support/CurrencyDescriptor.java +++ b/src/main/java/alfio/controller/api/support/CurrencyDescriptor.java @@ -17,13 +17,18 @@ package alfio.controller.api.support; import lombok.Getter; -import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor @Getter public class CurrencyDescriptor { private final String code; private final String name; private final String symbol; private final int fractionDigits; + + public CurrencyDescriptor(String code, String name, String symbol, int fractionDigits) { + this.code = code; + this.name = name; + this.symbol = symbol; + this.fractionDigits = fractionDigits; + } } diff --git a/src/main/java/alfio/manager/payment/stripe/StripeConnectResult.java b/src/main/java/alfio/controller/api/support/Description.java similarity index 76% rename from src/main/java/alfio/manager/payment/stripe/StripeConnectResult.java rename to src/main/java/alfio/controller/api/support/Description.java index c1b1de7690..db1ea3309e 100644 --- a/src/main/java/alfio/manager/payment/stripe/StripeConnectResult.java +++ b/src/main/java/alfio/controller/api/support/Description.java @@ -14,13 +14,9 @@ * You should have received a copy of the GNU General Public License * along with alf.io. If not, see . */ -package alfio.manager.payment.stripe; +package alfio.controller.api.support; -import lombok.Data; +import java.util.Map; -@Data -public class StripeConnectResult { - private final String accountId; - private final boolean success; - private final String errorMessage; +public record Description(String label, String placeholder, Map restrictedValuesDescription) { } diff --git a/src/main/java/alfio/controller/api/support/EventListItem.java b/src/main/java/alfio/controller/api/support/EventListItem.java index 9149dec469..c2f7fce031 100644 --- a/src/main/java/alfio/controller/api/support/EventListItem.java +++ b/src/main/java/alfio/controller/api/support/EventListItem.java @@ -26,6 +26,7 @@ public class EventListItem { + private static final int API_VERSION = 204; protected final Event event; private final String requestContextPath; private final List eventDescriptions; @@ -85,7 +86,7 @@ public String getTimeZone() { } public int getApiVersion() { - return 17; + return API_VERSION; } } diff --git a/src/main/java/alfio/controller/api/support/Field.java b/src/main/java/alfio/controller/api/support/Field.java new file mode 100644 index 0000000000..551e3cdd84 --- /dev/null +++ b/src/main/java/alfio/controller/api/support/Field.java @@ -0,0 +1,20 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.support; + +public record Field(int fieldIndex, String fieldValue) { +} diff --git a/src/main/java/alfio/controller/api/support/PageAndContent.java b/src/main/java/alfio/controller/api/support/PageAndContent.java index 02c3928d42..01cd65724b 100644 --- a/src/main/java/alfio/controller/api/support/PageAndContent.java +++ b/src/main/java/alfio/controller/api/support/PageAndContent.java @@ -16,12 +16,20 @@ */ package alfio.controller.api.support; -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor public class PageAndContent { private final T left; private final Integer right; + + public PageAndContent(T left, Integer right) { + this.left = left; + this.right = right; + } + + public Integer getRight() { + return right; + } + + public T getLeft() { + return left; + } } diff --git a/src/main/java/alfio/controller/api/support/PublicEventDescription.java b/src/main/java/alfio/controller/api/support/PublicEventDescription.java index 191ada497c..0e30c72c52 100644 --- a/src/main/java/alfio/controller/api/support/PublicEventDescription.java +++ b/src/main/java/alfio/controller/api/support/PublicEventDescription.java @@ -17,11 +17,10 @@ package alfio.controller.api.support; import alfio.model.EventDescription; -import lombok.experimental.Delegate; import org.apache.commons.lang3.StringUtils; public class PublicEventDescription { - @Delegate(excludes = {EventDescriptionExcludes.class}) + private final EventDescription eventDescription; PublicEventDescription(EventDescription eventDescription) { @@ -29,15 +28,19 @@ public class PublicEventDescription { } public String getShortDescription() { - return StringUtils.abbreviate(getDescription(), 100); + return StringUtils.abbreviate(eventDescription.description(), 100); + } + + public String getLocale() { + return eventDescription.locale(); + } + + public String getDescription() { + return eventDescription.description(); } static PublicEventDescription fromEventDescription(EventDescription eventDescription) { return new PublicEventDescription(eventDescription); } - interface EventDescriptionExcludes { - int getEventId(); - EventDescription.EventDescriptionType getEventDescriptionType(); - } } diff --git a/src/main/java/alfio/controller/api/support/TicketHelper.java b/src/main/java/alfio/controller/api/support/TicketHelper.java index daa40220d9..c2f2f9b2ac 100644 --- a/src/main/java/alfio/controller/api/support/TicketHelper.java +++ b/src/main/java/alfio/controller/api/support/TicketHelper.java @@ -26,12 +26,8 @@ import alfio.model.user.Organization; import alfio.repository.*; import alfio.repository.user.OrganizationRepository; -import alfio.util.EventUtil; -import alfio.util.LocaleUtil; -import alfio.util.TemplateManager; -import alfio.util.Validator; +import alfio.util.*; import alfio.util.Validator.AdvancedTicketAssignmentValidator; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; @@ -44,10 +40,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.util.stream.Collectors.*; - @Component -@AllArgsConstructor public class TicketHelper { private static final Set PENDING_RESERVATION_STATUSES = EnumSet.of(TicketReservation.TicketReservationStatus.PENDING, TicketReservation.TicketReservationStatus.OFFLINE_PAYMENT); @@ -63,8 +56,30 @@ public class TicketHelper { private final GroupManager groupManager; private final ConfigurationManager configurationManager; private final ExtensionManager extensionManager; - private final TicketReservationRepository ticketReservationRepository; - private final EventManager eventManager; + + public TicketHelper(TicketReservationManager ticketReservationManager, + OrganizationRepository organizationRepository, + TicketCategoryRepository ticketCategoryRepository, + TicketRepository ticketRepository, + TemplateManager templateManager, + TicketFieldRepository ticketFieldRepository, + AdditionalServiceItemRepository additionalServiceItemRepository, + EuVatChecker vatChecker, + GroupManager groupManager, + ConfigurationManager configurationManager, + ExtensionManager extensionManager) { + this.ticketReservationManager = ticketReservationManager; + this.organizationRepository = organizationRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketRepository = ticketRepository; + this.templateManager = templateManager; + this.ticketFieldRepository = ticketFieldRepository; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.vatChecker = vatChecker; + this.groupManager = groupManager; + this.configurationManager = configurationManager; + this.extensionManager = extensionManager; + } public Function> buildRetrieveFieldValuesFunction() { @@ -217,7 +232,7 @@ private void updateTicketOwner(UpdateTicketOwnerForm updateTicketOwner, Locale f private PartialTicketTextGenerator getOwnerChangeTextBuilder(Locale ticketLanguage, Ticket t, Event event) { Organization organization = organizationRepository.getById(event.getOrganizationId()); - String ticketUrl = ticketReservationManager.ticketUpdateUrl(event, t.getUuid()); + String ticketUrl = ReservationUtil.ticketUpdateUrl(event, t, configurationManager); return TemplateProcessor.buildEmailForOwnerChange(event, t, organization, ticketUrl, templateManager, ticketLanguage); } diff --git a/src/main/java/alfio/controller/api/support/WebhookApiController.java b/src/main/java/alfio/controller/api/support/WebhookApiController.java index 1bba048b73..1b497789f3 100644 --- a/src/main/java/alfio/controller/api/support/WebhookApiController.java +++ b/src/main/java/alfio/controller/api/support/WebhookApiController.java @@ -18,8 +18,6 @@ import alfio.manager.payment.StripeCreditCardManager; import alfio.util.RequestUtils; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -28,14 +26,16 @@ @RestController @RequestMapping("/api/webhook") -@AllArgsConstructor -@Log4j2 public class WebhookApiController { //private final MollieManager mollieManager; //private final TicketReservationManager ticketReservationManager; private final StripeCreditCardManager stripeCreditCardManager; + public WebhookApiController(StripeCreditCardManager stripeCreditCardManager) { + this.stripeCreditCardManager = stripeCreditCardManager; + } + @PostMapping("/mollie/event/{eventName}/reservation/{reservationId}") public void handleMollie(@PathVariable("eventName") String eventName, @PathVariable("reservationId") String reservationId) { // mollieManager.handleWebhook(eventName, reservationId, null); diff --git a/src/main/java/alfio/controller/api/v1/AttendeeApiController.java b/src/main/java/alfio/controller/api/v1/AttendeeApiController.java index 50db29d3a0..1e81f2f19d 100644 --- a/src/main/java/alfio/controller/api/v1/AttendeeApiController.java +++ b/src/main/java/alfio/controller/api/v1/AttendeeApiController.java @@ -27,9 +27,9 @@ import alfio.util.Wrappers; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.HttpStatus; @@ -48,9 +48,11 @@ @RestController @RequestMapping("/api/attendees") -@Log4j2 public class AttendeeApiController { + public static final String ALFIO_OPERATOR_HEADER = "Alfio-Operator"; + private static final Logger log = LoggerFactory.getLogger(AttendeeApiController.class); + private final AttendeeManager attendeeManager; @Autowired @@ -72,15 +74,19 @@ public ResponseEntity handleGenericException(RuntimeException e) { @PostMapping("/sponsor-scan") - public ResponseEntity scanBadge(@RequestBody SponsorScanRequest request, Principal principal) { - return ResponseEntity.ok(attendeeManager.registerSponsorScan(request.eventName, request.ticketIdentifier, request.notes, request.leadStatus, principal.getName())); + public ResponseEntity scanBadge(@RequestBody SponsorScanRequest request, + Principal principal, + @RequestHeader(name = ALFIO_OPERATOR_HEADER, required = false) String operator) { + return ResponseEntity.ok(attendeeManager.registerSponsorScan(request.eventName, request.ticketIdentifier, request.notes, request.leadStatus, principal.getName(), operator)); } @PostMapping("/sponsor-scan/bulk") - public ResponseEntity> scanBadges(@RequestBody List requests, Principal principal) { + public ResponseEntity> scanBadges(@RequestBody List requests, + Principal principal, + @RequestHeader(name = ALFIO_OPERATOR_HEADER, required = false) String operator) { String username = principal.getName(); return ResponseEntity.ok(requests.stream() - .map(request -> attendeeManager.registerSponsorScan(request.eventName, request.ticketIdentifier, request.notes, request.leadStatus, username)) + .map(request -> attendeeManager.registerSponsorScan(request.eventName, request.ticketIdentifier, request.notes, request.leadStatus, username, operator)) .collect(Collectors.toList())); } @@ -119,13 +125,28 @@ private static ResponseEntity notFound() { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - @Getter public static class SponsorScanRequest { private final String eventName; private final String ticketIdentifier; private final String notes; private final SponsorScan.LeadStatus leadStatus; + public String getEventName() { + return eventName; + } + + public String getTicketIdentifier() { + return ticketIdentifier; + } + + public String getNotes() { + return notes; + } + + public SponsorScan.LeadStatus getLeadStatus() { + return leadStatus; + } + @JsonCreator public SponsorScanRequest(@JsonProperty("eventName") String eventName, @JsonProperty("ticketIdentifier") String ticketIdentifier, diff --git a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java index 145c5ce1db..7971e6b28b 100644 --- a/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java +++ b/src/main/java/alfio/controller/api/v1/admin/EventApiV1Controller.java @@ -17,13 +17,20 @@ package alfio.controller.api.v1.admin; import alfio.extension.ExtensionService; +import alfio.job.executor.AssignTicketToSubscriberJobExecutor; import alfio.manager.*; +import alfio.manager.system.AdminJobManager; import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; import alfio.manager.user.UserManager; -import alfio.model.*; +import alfio.model.Event; +import alfio.model.EventWithAdditionalInfo; +import alfio.model.ExtensionSupport; import alfio.model.ExtensionSupport.ExtensionMetadataValue; +import alfio.model.PromoCodeDiscount; +import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.api.v1.admin.EventCreationRequest; +import alfio.model.api.v1.admin.LinkedSubscriptions; import alfio.model.group.Group; import alfio.model.modification.EventModification; import alfio.model.modification.LinkedGroupModification; @@ -34,10 +41,10 @@ import alfio.model.user.Organization; import alfio.repository.ExtensionRepository; import alfio.util.Json; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BeanPropertyBindingResult; @@ -46,23 +53,23 @@ import java.security.Principal; import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import static alfio.controller.api.admin.EventApiController.validateEvent; +import static alfio.manager.system.AdminJobExecutor.JobName.ASSIGN_TICKETS_TO_SUBSCRIBERS; +import static alfio.model.api.v1.admin.EventCreationRequest.findExistingCategory; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @RestController @RequestMapping("/api/v1/admin/event") -@AllArgsConstructor -@Log4j2 public class EventApiV1Controller { + private static final Logger log = LoggerFactory.getLogger(EventApiV1Controller.class); + private final EventManager eventManager; private final EventNameManager eventNameManager; private final FileUploadManager fileUploadManager; @@ -73,6 +80,34 @@ public class EventApiV1Controller { private final ExtensionService extensionService; private final ExtensionRepository extensionRepository; private final ConfigurationManager configurationManager; + private final AdminJobManager adminJobManager; + private final CheckInManager checkInManager; + + public EventApiV1Controller(EventManager eventManager, + EventNameManager eventNameManager, + FileUploadManager fileUploadManager, + FileDownloadManager fileDownloadManager, + UserManager userManager, + EventStatisticsManager eventStatisticsManager, + GroupManager groupManager, + ExtensionService extensionService, + ExtensionRepository extensionRepository, + ConfigurationManager configurationManager, + AdminJobManager adminJobManager, + CheckInManager checkInManager) { + this.eventManager = eventManager; + this.eventNameManager = eventNameManager; + this.fileUploadManager = fileUploadManager; + this.fileDownloadManager = fileDownloadManager; + this.userManager = userManager; + this.eventStatisticsManager = eventStatisticsManager; + this.groupManager = groupManager; + this.extensionService = extensionService; + this.extensionRepository = extensionRepository; + this.configurationManager = configurationManager; + this.adminJobManager = adminJobManager; + this.checkInManager = checkInManager; + } @PostMapping("/create") @Transactional @@ -90,6 +125,7 @@ public ResponseEntity create(@RequestBody EventCreationRequest request, .checkPrecondition(() -> isNotBlank(request.getImageUrl()), ErrorCode.custom("invalid.imageUrl", "Invalid Image URL")) .checkPrecondition(() -> isNotBlank(request.getTimezone()), ErrorCode.custom("invalid.timezone", "Invalid Timezone")) .checkPrecondition(() -> isNotBlank(imageRef), ErrorCode.custom("invalid.image", "Image is either missing or too big (max 200kb)")) + .checkPrecondition(() -> validateCategoriesSalesPeriod(request), ErrorCode.custom("invalid.categories", "Ticket categories: sales period not compatible with event dates")) .checkPrecondition(() -> { EventModification eventModification = request.toEventModification(organization, eventNameManager::generateShortName, imageRef); errorsContainer.set(new BeanPropertyBindingResult(eventModification, "event")); @@ -102,7 +138,7 @@ public ResponseEntity create(@RequestBody EventCreationRequest request, }, ErrorCode.lazy(() -> toErrorCode(errorsContainer.get()))) //TODO all location validation //TODO language validation, for all the description the same languages - .build(() -> insertEvent(request, user, imageRef).map(Event::getShortName).orElseThrow(IllegalStateException::new)); + .build(() -> insertEvent(request, user, imageRef).orElseThrow(IllegalStateException::new)); if(result.isSuccess()) { return ResponseEntity.ok(result.getData()); @@ -112,6 +148,12 @@ public ResponseEntity create(@RequestBody EventCreationRequest request, } + private boolean validateCategoriesSalesPeriod(EventCreationRequest request) { + var eventEnd = request.getEndDate(); + return request.getTickets().getCategories().stream() + .allMatch(tc -> tc.getStartSellingDate().isBefore(tc.getEndSellingDate()) && tc.getEndSellingDate().isBefore(eventEnd)); + } + private ErrorCode toErrorCode(Errors errors) { return errors.getFieldErrors().stream() .map(e -> ErrorCode.custom(e.getField(), e.getCode())) @@ -152,7 +194,7 @@ public ResponseEntity update(@PathVariable("slug") String slug, @Request String imageRef = fetchImage(request.getImageUrl()); Result result = new Result.Builder() - .build(() -> updateEvent(slug, request, user, imageRef).map(Event::getShortName).get()); + .build(() -> updateEvent(slug, request, user, imageRef).map(Event::getShortName).orElseThrow()); if(result.isSuccess()) { return ResponseEntity.ok(result.getData()); @@ -161,6 +203,57 @@ public ResponseEntity update(@PathVariable("slug") String slug, @Request } } + @GetMapping("/{slug}/subscriptions") + public ResponseEntity getLinkedSubscriptions(@PathVariable("slug") String slug, Principal user) { + + var subscriptionIdsOptional = eventManager.getOptionalEventAndOrganizationIdByName(slug, user.getName()) + .map(event -> retrieveLinkedSubscriptionsForEvent(slug, event.getId(), event.getOrganizationId())); + + return ResponseEntity.of(subscriptionIdsOptional); + } + + @PutMapping("/{slug}/subscriptions") + public ResponseEntity updateLinkedSubscriptions(@PathVariable("slug") String slug, + @RequestBody List subscriptions, + Principal user) { + var eventOptional = eventManager.getOptionalByName(slug, user.getName()); + if (eventOptional.isEmpty()) { + return ResponseEntity.badRequest().build(); + } + var eventAndOrgId = eventOptional.get(); + eventManager.updateLinkedSubscriptions(subscriptions, eventAndOrgId.getId(), eventAndOrgId.getOrganizationId()); + return ResponseEntity.ok(retrieveLinkedSubscriptionsForEvent(slug, eventAndOrgId.getId(), eventAndOrgId.getOrganizationId())); + } + + @PostMapping("/{slug}/generate-subscribers-tickets") + public ResponseEntity generateTicketsForSubscribers(@PathVariable("slug") String slug, + Principal user) { + return ResponseEntity.of(eventManager.getOptionalEventAndOrganizationIdByName(slug, user.getName()).map(eventAndOrganizationId -> { + Map params = Map.of( + AssignTicketToSubscriberJobExecutor.EVENT_ID, eventAndOrganizationId.getId(), + AssignTicketToSubscriberJobExecutor.ORGANIZATION_ID, eventAndOrganizationId.getOrganizationId(), + AssignTicketToSubscriberJobExecutor.FORCE_GENERATION, true + ); + return adminJobManager.scheduleExecution(ASSIGN_TICKETS_TO_SUBSCRIBERS, params); + })); + } + + @GetMapping("/{slug}/check-in-log") + public ResponseEntity> checkInLog(@PathVariable("slug") String slug, + Principal user) { + try { + return ResponseEntity.ok(checkInManager.retrieveLogEntries(slug, user.getName())); + } catch (Exception ex) { + log.error("Error while loading check-in log entries", ex); + return ResponseEntity.internalServerError().build(); + } + } + + private LinkedSubscriptions retrieveLinkedSubscriptionsForEvent(String slug, int id, int organizationId) { + var subscriptionIds = eventManager.getLinkedSubscriptionIds(id, organizationId); + return new LinkedSubscriptions(slug, subscriptionIds); + } + private Optional updateEvent(String slug, EventCreationRequest request, Principal user, String imageRef) { Organization organization = userManager.findUserOrganizations(user.getName()).get(0); EventWithAdditionalInfo original = eventStatisticsManager.getEventWithAdditionalInfo(slug,user.getName()); @@ -168,18 +261,22 @@ private Optional updateEvent(String slug, EventCreationRequest request, P Event event = original.getEvent(); - EventModification em = request.toEventModificationUpdate(original,organization,imageRef); + EventModification em = request.toEventModificationUpdate(original, organization, imageRef); eventManager.updateEventHeader(event, em, user.getName()); eventManager.updateEventPrices(event, em, user.getName()); if (em.getTicketCategories() != null && !em.getTicketCategories().isEmpty()) { - em.getTicketCategories().forEach(c -> - findCategoryByName(event, c.getName()).ifPresent(originalCategory -> - eventManager.updateCategory(originalCategory.getId(), event.getId(), c, user.getName()) - ) - ); + var existingCategories = original.getTicketCategories(); + em.getTicketCategories().forEach(c -> { + var existingCategory = findExistingCategory(existingCategories, c.getName(), c.getId()); + if (existingCategory.isPresent()) { + eventManager.updateCategory(existingCategory.get().getId(), event.getId(), c, user.getName()); + } else { + eventManager.insertCategory(event.getId(), c, user.getName()); + } + }); } @@ -188,26 +285,21 @@ private Optional updateEvent(String slug, EventCreationRequest request, P return eventManager.getOptionalByName(slug,user.getName()); } - private Optional findCategoryByName(Event event, String name) { - List categories = eventManager.loadTicketCategories(event); - return categories.stream().filter( oc -> oc.getName().equals(name)).findFirst(); - } - - private Optional insertEvent(EventCreationRequest request, Principal user, String imageRef) { - Organization organization = userManager.findUserOrganizations(user.getName()).get(0); - EventModification em = request.toEventModification(organization,eventNameManager::generateShortName,imageRef); - eventManager.createEvent(em, user.getName()); - Optional event = eventManager.getOptionalByName(em.getShortName(),user.getName()); - - event.ifPresent(e -> { + private Optional insertEvent(EventCreationRequest request, Principal user, String imageRef) { + try { + Organization organization = userManager.findUserOrganizations(user.getName()).get(0); + EventModification em = request.toEventModification(organization,eventNameManager::generateShortName,imageRef); + eventManager.createEvent(em, user.getName()); + var eventWithStatistics = eventStatisticsManager.getEventWithAdditionalInfo(em.getShortName(),user.getName()); + var event = eventWithStatistics.getEvent(); Optional.ofNullable(request.getTickets().getPromoCodes()).ifPresent(promoCodes -> promoCodes.forEach(pc -> //TODO add ref to categories eventManager.addPromoCode( pc.getName(), - e.getId(), + event.getId(), organization.getId(), - ZonedDateTime.of(pc.getValidFrom(),e.getZoneId()), - ZonedDateTime.of(pc.getValidTo(),e.getZoneId()), + ZonedDateTime.of(pc.getValidFrom(),event.getZoneId()), + ZonedDateTime.of(pc.getValidTo(),event.getZoneId()), pc.getDiscount(), pc.getDiscountType(), Collections.emptyList(), @@ -215,7 +307,8 @@ private Optional insertEvent(EventCreationRequest request, Principal user null, null, PromoCodeDiscount.CodeType.DISCOUNT, - null + null, + pc.getDiscountType() != PromoCodeDiscount.DiscountType.PERCENTAGE ? event.getCurrency() : null ) ) ); @@ -227,16 +320,16 @@ private Optional insertEvent(EventCreationRequest request, Principal user if(link.getRight().isPresent()) { Group group = link.getRight().get(); EventCreationRequest.CategoryRequest categoryRequest = link.getLeft(); - findCategoryByName(e, categoryRequest.getName()).ifPresent(category -> { + findExistingCategory(eventWithStatistics.getTicketCategories(), categoryRequest.getName(), categoryRequest.getId()).ifPresent(category -> { EventCreationRequest.GroupLinkRequest groupLinkRequest = categoryRequest.getGroupLink(); LinkedGroupModification modification = new LinkedGroupModification(null, group.getId(), - e.getId(), + event.getId(), category.getId(), groupLinkRequest.getType(), groupLinkRequest.getMatchType(), groupLinkRequest.getMaxAllocation()); - groupManager.createLink(group.getId(), e.getId(), modification); + groupManager.createLink(group.getId(), event.getId(), modification); }); } }); @@ -244,7 +337,7 @@ private Optional insertEvent(EventCreationRequest request, Principal user request.getExtensionSettings().stream() .collect(Collectors.groupingBy(EventCreationRequest.ExtensionSetting::getExtensionId)) .forEach((id,settings) -> { - List metadata = extensionService.getSingle(organization, e, id) + List metadata = extensionService.getSingle(organization, event, id) .map(es -> extensionRepository.findAllParametersForExtension(es.getId())) .orElseGet(Collections::emptyList); @@ -257,14 +350,16 @@ private Optional insertEvent(EventCreationRequest request, Principal user return pair.getRight().isPresent(); }) .map(pair -> new ExtensionMetadataValue(pair.getRight().get().getId(), pair.getLeft().getValue())) - .collect(Collectors.toList()); - extensionService.bulkUpdateEventSettings(organization, e, values); + .toList(); + extensionService.bulkUpdateEventSettings(organization, event, values); }); } - - }); - return event; + return Optional.of(event.getShortName()); + } catch (Exception ex) { + log.error("Error while inserting event", ex); + return Optional.empty(); + } } private String fetchImage(String url) { @@ -275,10 +370,4 @@ private String fetchImage(String url) { return null; } } - - - - - - } diff --git a/src/main/java/alfio/controller/api/v1/admin/OrganizationsApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/OrganizationsApiV1Controller.java new file mode 100644 index 0000000000..2dc6af089f --- /dev/null +++ b/src/main/java/alfio/controller/api/v1/admin/OrganizationsApiV1Controller.java @@ -0,0 +1,108 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.v1.admin; + +import alfio.manager.OrganizationDeleter; +import alfio.manager.user.UserManager; +import alfio.model.modification.OrganizationModification; +import alfio.model.user.Organization; +import alfio.model.user.Role; +import alfio.model.user.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; +import java.util.List; + +@RestController +@RequestMapping("/api/v1/admin/system/organization") +public class OrganizationsApiV1Controller { + private final UserManager userManager; + private final OrganizationDeleter organizationDeleter; + + @Autowired + public OrganizationsApiV1Controller(UserManager userManager, + OrganizationDeleter organizationDeleter) { + this.userManager = userManager; + this.organizationDeleter = organizationDeleter; + } + + @PostMapping("/create") + public ResponseEntity createOrganization(@RequestBody OrganizationModification om, Principal principal) { + if (om == null || !om.isValid(true)) { + return ResponseEntity.badRequest().build(); + } + int orgId = userManager.createOrganization(om, principal); + return ResponseEntity.ok(userManager.findOrganizationById(orgId, UserManager.ADMIN_USERNAME)); + } + + @GetMapping("/list") + public List getAllOrganizations() { + return userManager.findUserOrganizations(UserManager.ADMIN_USERNAME); + } + + @GetMapping("/{id}") + public ResponseEntity getSingleOrganization(@PathVariable("id") int organizationId) { + return ResponseEntity.of(userManager.findOptionalOrganizationById(organizationId, UserManager.ADMIN_USERNAME)); + } + + @PutMapping("/{id}/api-key") + public OrganizationApiKey createApiKeyForOrganization(@PathVariable("id") int organizationId, Principal principal) { + var user = userManager.insertUser(organizationId, null, null, null, null, Role.fromRoleName("ROLE_API_CLIENT"), User.Type.API_KEY, null, "Auto-generated API Key", principal); + return new OrganizationApiKey(organizationId, user.getUsername()); + } + + @PostMapping("/{id}") + public ResponseEntity update(@PathVariable("id") int organizationId, + @RequestBody OrganizationModification om, + Principal principal) { + if (om == null || !om.isValid(false) || organizationId != om.getId()) { + return ResponseEntity.badRequest().build(); + } + userManager.updateOrganization(om, principal); + return ResponseEntity.ok(userManager.findOrganizationById(organizationId, UserManager.ADMIN_USERNAME)); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable("id") int organizationId, Principal principal) { + boolean result = organizationDeleter.deleteOrganization(organizationId, principal); + if (result) { + return ResponseEntity.ok().build(); + } else { + return ResponseEntity.badRequest().build(); + } + } + + static class OrganizationApiKey { + private final int organizationId; + private final String apiKey; + + OrganizationApiKey(int organizationId, String apiKey) { + this.organizationId = organizationId; + this.apiKey = apiKey; + } + + public int getOrganizationId() { + return organizationId; + } + + public String getApiKey() { + return apiKey; + } + } +} diff --git a/src/main/java/alfio/controller/api/v1/admin/ReservationApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/ReservationApiV1Controller.java index 2f3f7e8a27..1f7ffe17a2 100644 --- a/src/main/java/alfio/controller/api/v1/admin/ReservationApiV1Controller.java +++ b/src/main/java/alfio/controller/api/v1/admin/ReservationApiV1Controller.java @@ -18,14 +18,23 @@ import alfio.manager.EventManager; import alfio.manager.PromoCodeRequestManager; +import alfio.manager.PurchaseContextManager; import alfio.manager.TicketReservationManager; -import alfio.model.api.v1.admin.ReservationCreationRequest; +import alfio.model.Event; +import alfio.model.PurchaseContext; +import alfio.model.PurchaseContext.PurchaseContextType; +import alfio.model.ReservationMetadata; +import alfio.model.api.v1.admin.ReservationAPICreationRequest; +import alfio.model.api.v1.admin.SubscriptionReservationCreationRequest; +import alfio.model.api.v1.admin.TicketReservationCreationRequest; import alfio.model.result.ErrorCode; +import alfio.model.subscription.SubscriptionDescriptor; import alfio.util.ReservationUtil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.web.bind.annotation.*; @@ -38,46 +47,44 @@ import static java.util.Objects.requireNonNullElseGet; @RestController -@RequestMapping("/api/v1/admin/event") +@RequestMapping("/api/v1/admin") public class ReservationApiV1Controller { private final TicketReservationManager ticketReservationManager; + private final PurchaseContextManager purchaseContextManager; private final EventManager eventManager; private final PromoCodeRequestManager promoCodeRequestManager; @Autowired public ReservationApiV1Controller(TicketReservationManager ticketReservationManager, - EventManager eventManager, - PromoCodeRequestManager promoCodeRequestManager) { + PurchaseContextManager purchaseContextManager, + PromoCodeRequestManager promoCodeRequestManager, + EventManager eventManager) { this.ticketReservationManager = ticketReservationManager; - this.eventManager = eventManager; + this.purchaseContextManager = purchaseContextManager; this.promoCodeRequestManager = promoCodeRequestManager; + this.eventManager = eventManager; } - @PostMapping("/{slug}/reservation") - public ResponseEntity createReservation(@PathVariable("slug") String eventSlug, - @RequestBody ReservationCreationRequest reservationCreationRequest, - Principal principal) { + @PostMapping("/event/{slug}/reservation") + @Transactional + public ResponseEntity createTicketsReservation(@PathVariable("slug") String eventSlug, + @RequestBody TicketReservationCreationRequest reservationCreationRequest, + Principal principal) { var bindingResult = new BeanPropertyBindingResult(reservationCreationRequest, "reservation"); - var optionalEvent = eventManager.getOptionalByName(eventSlug, principal.getName()); + var optionalEvent = purchaseContextManager.findBy(PurchaseContextType.event, eventSlug); if (optionalEvent.isEmpty()) { return ResponseEntity.notFound().build(); } - var event = optionalEvent.get(); + var event = (Event) optionalEvent.get(); Optional promoCodeDiscount = ReservationUtil.checkPromoCode(reservationCreationRequest, event, promoCodeRequestManager, bindingResult); var locale = Locale.forLanguageTag(requireNonNullElseGet(reservationCreationRequest.getLanguage(), () -> event.getContentLanguages().get(0).getLanguage())); var selected = ReservationUtil.validateCreateRequest(reservationCreationRequest, bindingResult, ticketReservationManager, eventManager, "", event); if(selected.isPresent() && !bindingResult.hasErrors()) { var pair = selected.get(); return ticketReservationManager.createTicketReservation(event, pair.getLeft(), pair.getRight(), promoCodeDiscount, locale, bindingResult, principal) - .map(id -> { - var user = reservationCreationRequest.getUser(); - if(user != null) { - ticketReservationManager.setReservationOwner(id, user.getUsername(), user.getEmail(), user.getFirstName(), user.getLastName(), locale.getLanguage()); - } - return ResponseEntity.ok(CreationResponse.success(id, ticketReservationManager.reservationUrlForExternalClients(id, event, locale.getLanguage(), user != null))); - }) + .map(id -> ResponseEntity.ok(postCreate(reservationCreationRequest, id, event, locale))) .orElseGet(() -> ResponseEntity.badRequest().build()); } else { return ResponseEntity.badRequest() @@ -85,6 +92,54 @@ public ResponseEntity createReservation(@PathVariable("slug") } } + @PostMapping("/subscription/{id}/reservation") + @Transactional + public ResponseEntity createSubscriptionReservation(@PathVariable("id") String subscriptionId, + @RequestBody SubscriptionReservationCreationRequest creationRequest, + Principal principal) { + var bindingResult = new BeanPropertyBindingResult(creationRequest, "reservation"); + + var optionalDescriptor = purchaseContextManager.findBy(PurchaseContextType.subscription, subscriptionId); + + if (optionalDescriptor.isEmpty()) { + return ResponseEntity.notFound().build(); + } + var subscriptionDescriptor = (SubscriptionDescriptor) optionalDescriptor.get(); + var locale = Locale.forLanguageTag(requireNonNullElseGet(creationRequest.getLanguage(), () -> subscriptionDescriptor.getContentLanguages().get(0).getLanguage())); + return ticketReservationManager.createSubscriptionReservation(subscriptionDescriptor, locale, bindingResult, principal, creationRequest.getMetadataOrNull()) + .map(id -> ResponseEntity.ok(postCreate(creationRequest, id, subscriptionDescriptor, locale))) + .orElseGet(() -> { + if (bindingResult.hasErrors()) { + return ResponseEntity.badRequest() + .body( + CreationResponse.error(bindingResult.getAllErrors().stream().map(err -> ErrorCode.custom("invalid."+err.getObjectName(), err.getCode())).collect(Collectors.toList())) + ); + } + return ResponseEntity.badRequest().build(); + }); + } + + private CreationResponse postCreate(ReservationAPICreationRequest creationRequest, + String id, + PurchaseContext purchaseContext, + Locale locale) { + var user = creationRequest.getUser(); + if(user != null) { + ticketReservationManager.setReservationOwner(id, user.getUsername(), user.getEmail(), user.getFirstName(), user.getLastName(), locale.getLanguage()); + } + var reservationConfiguration = creationRequest.getReservationConfiguration(); + if(reservationConfiguration != null) { + var reservationMetadata = new ReservationMetadata(reservationConfiguration.isHideContactData(), + false, + false, + reservationConfiguration.isHideConfirmationButtons(), + reservationConfiguration.isLockEmailEdit()); + ticketReservationManager.setReservationMetadata(id, reservationMetadata); + } + var subscriptionId = creationRequest instanceof TicketReservationCreationRequest ? ((TicketReservationCreationRequest) creationRequest).getSubscriptionId() : null; + return CreationResponse.success(id, ticketReservationManager.reservationUrlForExternalClients(id, purchaseContext, locale.getLanguage(), user != null, subscriptionId)); + } + public static class CreationResponse { private final String id; private final String href; diff --git a/src/main/java/alfio/controller/api/v1/admin/SubscriptionApiV1Controller.java b/src/main/java/alfio/controller/api/v1/admin/SubscriptionApiV1Controller.java new file mode 100644 index 0000000000..52c116a383 --- /dev/null +++ b/src/main/java/alfio/controller/api/v1/admin/SubscriptionApiV1Controller.java @@ -0,0 +1,158 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.v1.admin; + +import alfio.controller.api.admin.SubscriptionApiController; +import alfio.manager.EventManager; +import alfio.manager.FileDownloadManager; +import alfio.manager.FileUploadManager; +import alfio.manager.SubscriptionManager; +import alfio.manager.user.UserManager; +import alfio.model.api.v1.admin.SubscriptionDescriptorModificationRequest; +import alfio.model.modification.SubscriptionDescriptorModification; +import alfio.model.subscription.SubscriptionDescriptorWithStatistics; +import alfio.util.Json; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; +import java.util.List; +import java.util.UUID; + +import static alfio.controller.api.admin.SubscriptionApiController.loadLinkedEvents; + +@RestController +@RequestMapping("/api/v1/admin/subscription") +@Transactional +public class SubscriptionApiV1Controller { + private static final Logger log = LoggerFactory.getLogger(SubscriptionApiV1Controller.class); + private final SubscriptionManager subscriptionManager; + private final FileUploadManager fileUploadManager; + private final FileDownloadManager fileDownloadManager; + private final UserManager userManager; + private final EventManager eventManager; + + public SubscriptionApiV1Controller(SubscriptionManager subscriptionManager, + FileUploadManager fileUploadManager, + FileDownloadManager fileDownloadManager, + UserManager userManager, + EventManager eventManager) { + this.subscriptionManager = subscriptionManager; + this.fileUploadManager = fileUploadManager; + this.fileDownloadManager = fileDownloadManager; + this.userManager = userManager; + this.eventManager = eventManager; + } + + @PostMapping("/create") + public ResponseEntity create(@RequestBody SubscriptionDescriptorModificationRequest request, Principal principal) { + var organization = userManager.findUserOrganizations(principal.getName()).get(0); + String imageRef = null; + if(StringUtils.isNotEmpty(request.getImageUrl())) { + imageRef = fetchImage(request.getImageUrl()); + } + var modification = request.toDescriptorModification(null, organization.getId(), imageRef) + .flatMap(SubscriptionDescriptorModification::validate); + if (modification.isSuccess()) { + // request is valid + var optionalId = subscriptionManager.createSubscriptionDescriptor(modification.getData()); + return optionalId.map(uuid -> ResponseEntity.ok(uuid.toString())) + .orElseGet(() -> ResponseEntity.internalServerError().build()); + } + return ResponseEntity.badRequest().body(Json.toJson(modification.getErrors())); + + } + + @PostMapping("/{subscriptionId}/update") + public ResponseEntity update(@PathVariable("subscriptionId") UUID subscriptionId, + @RequestBody SubscriptionDescriptorModificationRequest request, Principal principal) { + var organization = userManager.findUserOrganizations(principal.getName()).get(0); + String imageRef = null; + if(StringUtils.isNotEmpty(request.getImageUrl())) { + imageRef = fetchImage(request.getImageUrl()); + } + var modification = request.toDescriptorModification(subscriptionId, organization.getId(), imageRef) + .flatMap(SubscriptionDescriptorModification::validate); + if (modification.isSuccess()) { + // request is valid + var optionalId = subscriptionManager.updateSubscriptionDescriptor(modification.getData()); + return optionalId.map(uuid -> ResponseEntity.ok(uuid.toString())) + .orElseGet(() -> ResponseEntity.internalServerError().build()); + } + return ResponseEntity.badRequest().body(Json.toJson(modification.getErrors())); + } + + @GetMapping("/{subscriptionId}") + public ResponseEntity get(@PathVariable("subscriptionId") UUID subscriptionId, + Principal principal) { + var organization = userManager.findUserOrganizations(principal.getName()).get(0); + return ResponseEntity.of(subscriptionManager.loadSubscriptionWithStatistics(subscriptionId, organization.getId())); + } + + @GetMapping("/{subscriptionId}/events") + public ResponseEntity> getLinkedEvents(@PathVariable("subscriptionId") UUID subscriptionId, + Principal principal) { + var organization = userManager.findUserOrganizations(principal.getName()).get(0); + return ResponseEntity.ok(loadLinkedEvents(subscriptionManager.getLinkedEvents(organization.getId(), subscriptionId))); + } + + @PostMapping("/{subscriptionId}/events") + public ResponseEntity> updateLinkedEvents(@PathVariable("subscriptionId") UUID subscriptionId, + @RequestBody List eventSlugs, + Principal principal) { + if (eventSlugs == null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + var organization = userManager.findUserOrganizations(principal.getName()).get(0); + int organizationId = organization.getId(); + + List eventIds = List.of(); + if (!eventSlugs.isEmpty()) { + eventIds = eventManager.getEventIdsBySlug(eventSlugs, organizationId); + } + var result = subscriptionManager.updateLinkedEvents(organizationId, subscriptionId, eventIds); + if (result.isSuccess()) { + return ResponseEntity.ok(loadLinkedEvents(result.getData())); + } else { + if (log.isWarnEnabled()) { + log.warn("Cannot update linked events {}", Json.toJson(result.getErrors())); + } + return ResponseEntity.badRequest().build(); + } + } + + @DeleteMapping("/{subscriptionId}/deactivate") + public ResponseEntity deactivate(@PathVariable("subscriptionId") UUID descriptorId, Principal principal) { + var organization = userManager.findUserOrganizations(principal.getName()).get(0); + int organizationId = organization.getId(); + return SubscriptionApiController.deactivateSubscriptionDescriptor(organizationId, descriptorId, subscriptionManager); + } + + private String fetchImage(String url) { + if(url != null) { + FileDownloadManager.DownloadedFile file = fileDownloadManager.downloadFile(url); + return file != null ? fileUploadManager.insertFile(file.toUploadBase64FileModification()) : null; + } else { + return null; + } + } +} diff --git a/src/main/java/alfio/controller/api/v2/InfoApiController.java b/src/main/java/alfio/controller/api/v2/InfoApiController.java index ada7168c22..9bc2611af7 100644 --- a/src/main/java/alfio/controller/api/v2/InfoApiController.java +++ b/src/main/java/alfio/controller/api/v2/InfoApiController.java @@ -18,7 +18,6 @@ import alfio.controller.api.v2.model.AlfioInfo; import alfio.manager.system.ConfigurationManager; -import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -27,11 +26,14 @@ @RestController @RequestMapping("/api/v2/") -@AllArgsConstructor public class InfoApiController { private final ConfigurationManager configurationManager; + public InfoApiController(ConfigurationManager configurationManager) { + this.configurationManager = configurationManager; + } + @GetMapping("info") public AlfioInfo getInfo(HttpSession session) { return configurationManager.getInfo(session); diff --git a/src/main/java/alfio/controller/api/v2/TranslationsApiController.java b/src/main/java/alfio/controller/api/v2/TranslationsApiController.java index d493753c05..736322870e 100644 --- a/src/main/java/alfio/controller/api/v2/TranslationsApiController.java +++ b/src/main/java/alfio/controller/api/v2/TranslationsApiController.java @@ -24,7 +24,6 @@ import alfio.manager.system.ConfigurationManager; import alfio.model.system.ConfigurationKeys; import alfio.util.LocaleUtil; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.tuple.Pair; import org.springframework.web.bind.annotation.*; @@ -35,7 +34,6 @@ import java.util.stream.Collectors; @RestController -@AllArgsConstructor @RequestMapping("/api/v2/") public class TranslationsApiController { @@ -43,16 +41,22 @@ public class TranslationsApiController { private final ConfigurationManager configurationManager; private final I18nManager i18nManager; + public TranslationsApiController(MessageSourceManager messageSourceManager, ConfigurationManager configurationManager, I18nManager i18nManager) { + this.messageSourceManager = messageSourceManager; + this.configurationManager = configurationManager; + this.i18nManager = i18nManager; + } + @GetMapping("/public/i18n/bundle/{lang}") public Map getPublicTranslations(@PathVariable("lang") String lang, @RequestParam(value = "withSystemOverride", defaultValue = "true", required = false) boolean withSystemOverride) { - return messageSourceManager.getBundleAsMap("alfio.i18n.public", withSystemOverride, lang); + return messageSourceManager.getBundleAsMap("alfio.i18n.public", withSystemOverride, lang, MessageSourceManager.PUBLIC_FRONTEND); } @GetMapping("/admin/i18n/bundle/{lang}") public Map getAdminTranslations(@PathVariable("lang") String lang, @RequestParam(value = "withSystemOverride", defaultValue = "true", required = false) boolean withSystemOverride) { - return messageSourceManager.getBundleAsMap("alfio.i18n.admin", withSystemOverride, lang); + return messageSourceManager.getBundleAsMap("alfio.i18n.public", withSystemOverride, lang, MessageSourceManager.ADMIN_FRONTEND); } @GetMapping("/public/i18n/countries/{lang}") diff --git a/src/main/java/alfio/controller/api/v2/model/AdditionalService.java b/src/main/java/alfio/controller/api/v2/model/AdditionalService.java index 208cccfe18..d9c2aef3f6 100644 --- a/src/main/java/alfio/controller/api/v2/model/AdditionalService.java +++ b/src/main/java/alfio/controller/api/v2/model/AdditionalService.java @@ -16,12 +16,10 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Map; -@AllArgsConstructor @Getter public class AdditionalService { @@ -52,4 +50,44 @@ public class AdditionalService { private final Map title; private final Map description; + + public AdditionalService(int id, + alfio.model.AdditionalService.AdditionalServiceType type, + alfio.model.AdditionalService.SupplementPolicy supplementPolicy, + boolean fixPrice, + int availableQuantity, + int maxQtyPerOrder, + boolean free, + String formattedFinalPrice, + boolean hasDiscount, + String formattedDiscountedPrice, + boolean vatApplies, + boolean vatIncluded, + String vatPercentage, + boolean expired, + boolean saleInFuture, + Map formattedInception, + Map formattedExpiration, + Map title, + Map description) { + this.id = id; + this.type = type; + this.supplementPolicy = supplementPolicy; + this.fixPrice = fixPrice; + this.availableQuantity = availableQuantity; + this.maxQtyPerOrder = maxQtyPerOrder; + this.free = free; + this.formattedFinalPrice = formattedFinalPrice; + this.hasDiscount = hasDiscount; + this.formattedDiscountedPrice = formattedDiscountedPrice; + this.vatApplies = vatApplies; + this.vatIncluded = vatIncluded; + this.vatPercentage = vatPercentage; + this.expired = expired; + this.saleInFuture = saleInFuture; + this.formattedInception = formattedInception; + this.formattedExpiration = formattedExpiration; + this.title = title; + this.description = description; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java b/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java index 6524e7c273..26f5ceef8d 100644 --- a/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/AlfioInfo.java @@ -17,11 +17,9 @@ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; @Getter -@AllArgsConstructor public class AlfioInfo { private final boolean demoModeEnabled; @@ -31,4 +29,26 @@ public class AlfioInfo { private final String globalPrivacyPolicyUrl; private final String globalTermsUrl; private final InvoicingConfiguration invoicingConfiguration; + private final String announcementBannerContentHTML; + private final WalletConfiguration walletConfiguration; + + public AlfioInfo(boolean demoModeEnabled, + boolean devModeEnabled, + boolean prodModeEnabled, + AnalyticsConfiguration analyticsConfiguration, + String globalPrivacyPolicyUrl, + String globalTermsUrl, + InvoicingConfiguration invoicingConfiguration, + String announcementBannerContentHTML, + WalletConfiguration walletConfiguration) { + this.demoModeEnabled = demoModeEnabled; + this.devModeEnabled = devModeEnabled; + this.prodModeEnabled = prodModeEnabled; + this.analyticsConfiguration = analyticsConfiguration; + this.globalPrivacyPolicyUrl = globalPrivacyPolicyUrl; + this.globalTermsUrl = globalTermsUrl; + this.invoicingConfiguration = invoicingConfiguration; + this.announcementBannerContentHTML = announcementBannerContentHTML; + this.walletConfiguration = walletConfiguration; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/AnalyticsConfiguration.java b/src/main/java/alfio/controller/api/v2/model/AnalyticsConfiguration.java index 94068d1ac3..cc96437282 100644 --- a/src/main/java/alfio/controller/api/v2/model/AnalyticsConfiguration.java +++ b/src/main/java/alfio/controller/api/v2/model/AnalyticsConfiguration.java @@ -18,7 +18,6 @@ import alfio.manager.system.ConfigurationManager; import alfio.model.system.ConfigurationKeys; -import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; @@ -29,13 +28,18 @@ import static alfio.model.system.ConfigurationKeys.GOOGLE_ANALYTICS_ANONYMOUS_MODE; import static alfio.model.system.ConfigurationKeys.GOOGLE_ANALYTICS_KEY; -@AllArgsConstructor @Getter public class AnalyticsConfiguration { private final String googleAnalyticsKey; private final boolean googleAnalyticsScrambledInfo; //<- see GOOGLE_ANALYTICS_ANONYMOUS_MODE private final String clientId; + public AnalyticsConfiguration(String googleAnalyticsKey, boolean googleAnalyticsScrambledInfo, String clientId) { + this.googleAnalyticsKey = googleAnalyticsKey; + this.googleAnalyticsScrambledInfo = googleAnalyticsScrambledInfo; + this.clientId = clientId; + } + public static AnalyticsConfiguration build(Map conf, HttpSession session) { var googAnalyticsKey = StringUtils.trimToNull(conf.get(GOOGLE_ANALYTICS_KEY).getValueOrNull()); diff --git a/src/main/java/alfio/controller/api/v2/model/ApiPurchaseContext.java b/src/main/java/alfio/controller/api/v2/model/ApiPurchaseContext.java index 2209ca0245..40075c8d65 100644 --- a/src/main/java/alfio/controller/api/v2/model/ApiPurchaseContext.java +++ b/src/main/java/alfio/controller/api/v2/model/ApiPurchaseContext.java @@ -30,7 +30,12 @@ public interface ApiPurchaseContext { InvoicingConfiguration getInvoicingConfiguration(); EventWithAdditionalInfo.AssignmentConfiguration getAssignmentConfiguration(); AnalyticsConfiguration getAnalyticsConfiguration(); + + OfflinePaymentConfiguration getOfflinePaymentConfiguration(); EventWithAdditionalInfo.CaptchaConfiguration getCaptchaConfiguration(); + + EmbeddingConfiguration getEmbeddingConfiguration(); + boolean isVatIncluded(); boolean isFree(); String getCurrency(); diff --git a/src/main/java/alfio/controller/api/v2/model/BasicEventInfo.java b/src/main/java/alfio/controller/api/v2/model/BasicEventInfo.java index e5801f9493..0b24aaca41 100644 --- a/src/main/java/alfio/controller/api/v2/model/BasicEventInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/BasicEventInfo.java @@ -17,13 +17,11 @@ package alfio.controller.api.v2.model; import alfio.model.Event.EventFormat; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.List; import java.util.Map; -@AllArgsConstructor @Getter public class BasicEventInfo implements DateValidity { @@ -41,4 +39,32 @@ public class BasicEventInfo implements DateValidity { private final Map formattedEndDate; private final Map formattedEndTime; private final List contentLanguages; + + public BasicEventInfo(String shortName, + String fileBlobId, + Map title, + EventFormat format, + String location, + String timeZone, + DatesWithTimeZoneOffset datesWithOffset, + boolean sameDay, + Map formattedBeginDate, + Map formattedBeginTime, + Map formattedEndDate, + Map formattedEndTime, + List contentLanguages) { + this.shortName = shortName; + this.fileBlobId = fileBlobId; + this.title = title; + this.format = format; + this.location = location; + this.timeZone = timeZone; + this.datesWithOffset = datesWithOffset; + this.sameDay = sameDay; + this.formattedBeginDate = formattedBeginDate; + this.formattedBeginTime = formattedBeginTime; + this.formattedEndDate = formattedEndDate; + this.formattedEndTime = formattedEndTime; + this.contentLanguages = contentLanguages; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/BasicSubscriptionDescriptorInfo.java b/src/main/java/alfio/controller/api/v2/model/BasicSubscriptionDescriptorInfo.java index 9d48046648..3371f87a0b 100644 --- a/src/main/java/alfio/controller/api/v2/model/BasicSubscriptionDescriptorInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/BasicSubscriptionDescriptorInfo.java @@ -20,7 +20,6 @@ import alfio.model.subscription.SubscriptionDescriptor.SubscriptionTimeUnit; import alfio.model.subscription.SubscriptionDescriptor.SubscriptionUsageType; import alfio.model.subscription.SubscriptionDescriptor.SubscriptionValidityType; -import lombok.AllArgsConstructor; import lombok.Getter; import java.math.BigDecimal; @@ -30,7 +29,6 @@ import java.util.UUID; @Getter -@AllArgsConstructor public class BasicSubscriptionDescriptorInfo { private final UUID id; private final String fileBlobId; @@ -62,4 +60,52 @@ public class BasicSubscriptionDescriptorInfo { private final Map formattedValidTo; private final List contentLanguages; + + public BasicSubscriptionDescriptorInfo(UUID id, + String fileBlobId, + Map title, + Map description, + DatesWithTimeZoneOffset salePeriod, + SubscriptionValidityType validityType, + SubscriptionUsageType usageType, + ZoneId timeZone, + SubscriptionTimeUnit validityTimeUnit, + Integer validityUnits, + Integer maxEntries, + String organizationEmail, + String organizationName, + String formattedPrice, + String currency, + CurrencyDescriptor currencyDescriptor, + BigDecimal vat, + boolean vatIncluded, + Map formattedOnSaleFrom, + Map formattedOnSaleTo, + Map formattedValidFrom, + Map formattedValidTo, + List contentLanguages) { + this.id = id; + this.fileBlobId = fileBlobId; + this.title = title; + this.description = description; + this.salePeriod = salePeriod; + this.validityType = validityType; + this.usageType = usageType; + this.timeZone = timeZone; + this.validityTimeUnit = validityTimeUnit; + this.validityUnits = validityUnits; + this.maxEntries = maxEntries; + this.organizationEmail = organizationEmail; + this.organizationName = organizationName; + this.formattedPrice = formattedPrice; + this.currency = currency; + this.currencyDescriptor = currencyDescriptor; + this.vat = vat; + this.vatIncluded = vatIncluded; + this.formattedOnSaleFrom = formattedOnSaleFrom; + this.formattedOnSaleTo = formattedOnSaleTo; + this.formattedValidFrom = formattedValidFrom; + this.formattedValidTo = formattedValidTo; + this.contentLanguages = contentLanguages; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/ClientRedirect.java b/src/main/java/alfio/controller/api/v2/model/ClientRedirect.java index 79765c36ac..5703ea5ba4 100644 --- a/src/main/java/alfio/controller/api/v2/model/ClientRedirect.java +++ b/src/main/java/alfio/controller/api/v2/model/ClientRedirect.java @@ -16,15 +16,17 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @Getter -@AllArgsConstructor public class ClientRedirect { private final String targetUrl; + public ClientRedirect(String targetUrl) { + this.targetUrl = targetUrl; + } + public boolean isEmpty() { return StringUtils.isBlank(targetUrl); } diff --git a/src/main/java/alfio/controller/api/v2/model/DynamicDiscount.java b/src/main/java/alfio/controller/api/v2/model/DynamicDiscount.java index 31a567daf1..6cf029fb9e 100644 --- a/src/main/java/alfio/controller/api/v2/model/DynamicDiscount.java +++ b/src/main/java/alfio/controller/api/v2/model/DynamicDiscount.java @@ -17,13 +17,10 @@ package alfio.controller.api.v2.model; import alfio.model.PromoCodeDiscount; -import lombok.Data; import java.util.Map; -@Data -public class DynamicDiscount { - private final String discount; - private final PromoCodeDiscount.DiscountType discountType; - private final Map formattedMessage; +public record DynamicDiscount(String discount, + PromoCodeDiscount.DiscountType discountType, + Map formattedMessage) { } diff --git a/src/main/java/alfio/config/authentication/AuthenticationConstants.java b/src/main/java/alfio/controller/api/v2/model/EmbeddingConfiguration.java similarity index 53% rename from src/main/java/alfio/config/authentication/AuthenticationConstants.java rename to src/main/java/alfio/controller/api/v2/model/EmbeddingConfiguration.java index fbb0827a8d..8bbd1ce648 100644 --- a/src/main/java/alfio/config/authentication/AuthenticationConstants.java +++ b/src/main/java/alfio/controller/api/v2/model/EmbeddingConfiguration.java @@ -14,19 +14,22 @@ * You should have received a copy of the GNU General Public License * along with alf.io. If not, see . */ -package alfio.config.authentication; +package alfio.controller.api.v2.model; -import lombok.experimental.UtilityClass; +import java.util.Objects; -@UtilityClass -public class AuthenticationConstants { - public static final String OPERATOR = "OPERATOR"; - public static final String SPONSOR = "SPONSOR"; - static final String ADMIN_API = "/admin/api"; - static final String ADMIN_PUBLIC_API = "/api/v1/admin"; - static final String SUPERVISOR = "SUPERVISOR"; - static final String ADMIN = "ADMIN"; - static final String OWNER = "OWNER"; - static final String API_CLIENT = "API_CLIENT"; - static final String X_REQUESTED_WITH = "X-Requested-With"; +public class EmbeddingConfiguration { + private final String notificationOrigin; + + public EmbeddingConfiguration(String notificationOrigin) { + this.notificationOrigin = Objects.requireNonNullElse(notificationOrigin, ""); + } + + public boolean isEnabled() { + return notificationOrigin != null && !notificationOrigin.isBlank(); + } + + public String getNotificationOrigin() { + return notificationOrigin; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/EventCode.java b/src/main/java/alfio/controller/api/v2/model/EventCode.java index 681c000c0d..288afd4bb5 100644 --- a/src/main/java/alfio/controller/api/v2/model/EventCode.java +++ b/src/main/java/alfio/controller/api/v2/model/EventCode.java @@ -17,10 +17,8 @@ package alfio.controller.api.v2.model; import alfio.model.PromoCodeDiscount; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class EventCode { @@ -29,6 +27,13 @@ public class EventCode { private final PromoCodeDiscount.DiscountType discountType; private final String discountAmount; + public EventCode(String code, EventCodeType type, PromoCodeDiscount.DiscountType discountType, String discountAmount) { + this.code = code; + this.type = type; + this.discountType = discountType; + this.discountAmount = discountAmount; + } + public enum EventCodeType { @Deprecated SPECIAL_PRICE, DISCOUNT, ACCESS } diff --git a/src/main/java/alfio/controller/api/v2/model/EventWithAdditionalInfo.java b/src/main/java/alfio/controller/api/v2/model/EventWithAdditionalInfo.java index 2a794d4755..eadff8876e 100644 --- a/src/main/java/alfio/controller/api/v2/model/EventWithAdditionalInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/EventWithAdditionalInfo.java @@ -21,13 +21,11 @@ import alfio.model.PurchaseContext; import alfio.model.user.Organization; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.List; import java.util.Map; -@AllArgsConstructor public class EventWithAdditionalInfo implements DateValidity, ApiPurchaseContext { private final Event event; private final String mapUrl; @@ -64,6 +62,10 @@ public class EventWithAdditionalInfo implements DateValidity, ApiPurchaseContext private final AnalyticsConfiguration analyticsConfiguration; + private final OfflinePaymentConfiguration offlinePaymentConfiguration; + + private final EmbeddingConfiguration embeddingConfiguration; + private final Map> i18nOverride; private final Integer availableTicketsCount; @@ -72,6 +74,50 @@ public class EventWithAdditionalInfo implements DateValidity, ApiPurchaseContext private final boolean canApplySubscriptions; + public EventWithAdditionalInfo(Event event, + String mapUrl, + Organization.OrganizationContact organization, + Map description, + String bankAccount, + List bankAccountOwner, + Map formattedBeginDate, + Map formattedBeginTime, + Map formattedEndDate, + Map formattedEndTime, + InvoicingConfiguration invoicingConfiguration, + CaptchaConfiguration captchaConfiguration, + AssignmentConfiguration assignmentConfiguration, + PromotionsConfiguration promotionsConfiguration, + AnalyticsConfiguration analyticsConfiguration, + OfflinePaymentConfiguration offlinePaymentConfiguration, + EmbeddingConfiguration embeddingConfiguration, + Map> i18nOverride, + Integer availableTicketsCount, + String customCss, + boolean canApplySubscriptions) { + this.event = event; + this.mapUrl = mapUrl; + this.organization = organization; + this.description = description; + this.bankAccount = bankAccount; + this.bankAccountOwner = bankAccountOwner; + this.formattedBeginDate = formattedBeginDate; + this.formattedBeginTime = formattedBeginTime; + this.formattedEndDate = formattedEndDate; + this.formattedEndTime = formattedEndTime; + this.invoicingConfiguration = invoicingConfiguration; + this.captchaConfiguration = captchaConfiguration; + this.assignmentConfiguration = assignmentConfiguration; + this.promotionsConfiguration = promotionsConfiguration; + this.analyticsConfiguration = analyticsConfiguration; + this.offlinePaymentConfiguration = offlinePaymentConfiguration; + this.embeddingConfiguration = embeddingConfiguration; + this.i18nOverride = i18nOverride; + this.availableTicketsCount = availableTicketsCount; + this.customCss = customCss; + this.canApplySubscriptions = canApplySubscriptions; + } + public String getShortName() { return event.getShortName(); } @@ -236,27 +282,52 @@ public Map getTitle() { return event.getTitle(); } - @AllArgsConstructor + + @Override + public OfflinePaymentConfiguration getOfflinePaymentConfiguration() { + return offlinePaymentConfiguration; + } + + @Override + public EmbeddingConfiguration getEmbeddingConfiguration() { + return embeddingConfiguration; + } + @Getter public static class CaptchaConfiguration { private final boolean captchaForTicketSelection; private final boolean captchaForOfflinePaymentAndFree; private final String recaptchaApiKey; + + public CaptchaConfiguration(boolean captchaForTicketSelection, boolean captchaForOfflinePaymentAndFree, String recaptchaApiKey) { + this.captchaForTicketSelection = captchaForTicketSelection; + this.captchaForOfflinePaymentAndFree = captchaForOfflinePaymentAndFree; + this.recaptchaApiKey = recaptchaApiKey; + } } - @AllArgsConstructor @Getter public static class AssignmentConfiguration { private final boolean forceAssignment; private final boolean enableAttendeeAutocomplete; private final boolean enableTicketTransfer; + + public AssignmentConfiguration(boolean forceAssignment, boolean enableAttendeeAutocomplete, boolean enableTicketTransfer) { + this.forceAssignment = forceAssignment; + this.enableAttendeeAutocomplete = enableAttendeeAutocomplete; + this.enableTicketTransfer = enableTicketTransfer; + } } - @AllArgsConstructor @Getter public static class PromotionsConfiguration { private final boolean hasAccessPromotions; private final boolean usePartnerCode; + + public PromotionsConfiguration(boolean hasAccessPromotions, boolean usePartnerCode) { + this.hasAccessPromotions = hasAccessPromotions; + this.usePartnerCode = usePartnerCode; + } } @JsonIgnore diff --git a/src/main/java/alfio/controller/api/v2/model/InvoicingConfiguration.java b/src/main/java/alfio/controller/api/v2/model/InvoicingConfiguration.java index 9a34e19e42..bae57fab8a 100644 --- a/src/main/java/alfio/controller/api/v2/model/InvoicingConfiguration.java +++ b/src/main/java/alfio/controller/api/v2/model/InvoicingConfiguration.java @@ -16,10 +16,8 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class InvoicingConfiguration { private final boolean userCanDownloadReceiptOrInvoice; @@ -29,4 +27,20 @@ public class InvoicingConfiguration { private final boolean customerReferenceEnabled; private final boolean enabledItalyEInvoicing; private final boolean vatNumberStrictlyRequired; + + public InvoicingConfiguration(boolean userCanDownloadReceiptOrInvoice, + boolean euVatCheckingEnabled, + boolean invoiceAllowed, + boolean onlyInvoice, + boolean customerReferenceEnabled, + boolean enabledItalyEInvoicing, + boolean vatNumberStrictlyRequired) { + this.userCanDownloadReceiptOrInvoice = userCanDownloadReceiptOrInvoice; + this.euVatCheckingEnabled = euVatCheckingEnabled; + this.invoiceAllowed = invoiceAllowed; + this.onlyInvoice = onlyInvoice; + this.customerReferenceEnabled = customerReferenceEnabled; + this.enabledItalyEInvoicing = enabledItalyEInvoicing; + this.vatNumberStrictlyRequired = vatNumberStrictlyRequired; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/ItemsByCategory.java b/src/main/java/alfio/controller/api/v2/model/ItemsByCategory.java index 678c36bbce..4a4c9c2a41 100644 --- a/src/main/java/alfio/controller/api/v2/model/ItemsByCategory.java +++ b/src/main/java/alfio/controller/api/v2/model/ItemsByCategory.java @@ -16,12 +16,10 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.List; -@AllArgsConstructor @Getter public class ItemsByCategory { @@ -33,11 +31,28 @@ public class ItemsByCategory { private final boolean preSales; private final List ticketCategoriesForWaitingList; + public ItemsByCategory(List ticketCategories, + List expiredCategories, + List additionalServices, + boolean waitingList, + boolean preSales, + List ticketCategoriesForWaitingList) { + this.ticketCategories = ticketCategories; + this.expiredCategories = expiredCategories; + this.additionalServices = additionalServices; + this.waitingList = waitingList; + this.preSales = preSales; + this.ticketCategoriesForWaitingList = ticketCategoriesForWaitingList; + } - @AllArgsConstructor @Getter public static class TicketCategoryForWaitingList { private final int id; private final String name; + + public TicketCategoryForWaitingList(int id, String name) { + this.id = id; + this.name = name; + } } } diff --git a/src/main/java/alfio/controller/api/v2/model/Language.java b/src/main/java/alfio/controller/api/v2/model/Language.java index 01f9946b8a..c659cfb694 100644 --- a/src/main/java/alfio/controller/api/v2/model/Language.java +++ b/src/main/java/alfio/controller/api/v2/model/Language.java @@ -16,12 +16,15 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class Language { private final String locale; private final String displayLanguage; + + public Language(String locale, String displayLanguage) { + this.locale = locale; + this.displayLanguage = displayLanguage; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/LocalizedCountry.java b/src/main/java/alfio/controller/api/v2/model/LocalizedCountry.java index 67d2c67839..af6a2f0732 100644 --- a/src/main/java/alfio/controller/api/v2/model/LocalizedCountry.java +++ b/src/main/java/alfio/controller/api/v2/model/LocalizedCountry.java @@ -16,12 +16,15 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class LocalizedCountry { private final String isoCode; private final String name; + + public LocalizedCountry(String isoCode, String name) { + this.isoCode = isoCode; + this.name = name; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/OfflinePaymentConfiguration.java b/src/main/java/alfio/controller/api/v2/model/OfflinePaymentConfiguration.java new file mode 100644 index 0000000000..1fb033fe95 --- /dev/null +++ b/src/main/java/alfio/controller/api/v2/model/OfflinePaymentConfiguration.java @@ -0,0 +1,29 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.v2.model; + +public class OfflinePaymentConfiguration { + private final boolean showOnlyBasicInstructions; + + public OfflinePaymentConfiguration(boolean showOnlyBasicInstructions) { + this.showOnlyBasicInstructions = showOnlyBasicInstructions; + } + + public boolean isShowOnlyBasicInstructions() { + return showOnlyBasicInstructions; + } +} diff --git a/src/main/java/alfio/controller/api/v2/model/OnlineCheckInInfo.java b/src/main/java/alfio/controller/api/v2/model/OnlineCheckInInfo.java index 02f226f99c..b7f7446e04 100644 --- a/src/main/java/alfio/controller/api/v2/model/OnlineCheckInInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/OnlineCheckInInfo.java @@ -16,22 +16,17 @@ */ package alfio.controller.api.v2.model; -import alfio.controller.support.FormattedEventDates; -import alfio.controller.support.Formatters; import alfio.model.checkin.EventWithCheckInInfo; import alfio.model.metadata.JoinLink; -import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.context.MessageSource; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.List; import java.util.Map; import static alfio.controller.support.Formatters.getFormattedDate; -@AllArgsConstructor @Getter public class OnlineCheckInInfo implements DateValidity { @@ -43,6 +38,20 @@ public class OnlineCheckInInfo implements DateValidity { private final String timeZone; private final DatesWithTimeZoneOffset datesWithOffset; + public OnlineCheckInInfo(Map formattedBeginDate, + Map formattedBeginTime, + Map formattedEndDate, + Map formattedEndTime, + String timeZone, + DatesWithTimeZoneOffset datesWithOffset) { + this.formattedBeginDate = formattedBeginDate; + this.formattedBeginTime = formattedBeginTime; + this.formattedEndDate = formattedEndDate; + this.formattedEndTime = formattedEndTime; + this.timeZone = timeZone; + this.datesWithOffset = datesWithOffset; + } + public boolean isSameDay() { return true; } @@ -58,8 +67,8 @@ public static OnlineCheckInInfo fromJoinLink(JoinLink joinLink, EventWithCheckInInfo event, ZoneId targetTz, MessageSource messageSource) { - var start = joinLink.getValidFrom().atZone(event.getZoneId()); - var end = joinLink.getValidFrom().atZone(event.getZoneId()); + var start = joinLink.validFrom().atZone(event.getZoneId()); + var end = joinLink.validFrom().atZone(event.getZoneId()); return fromDates(event, start, end, targetTz, messageSource); } diff --git a/src/main/java/alfio/controller/api/v2/model/PaymentProxyWithParameters.java b/src/main/java/alfio/controller/api/v2/model/PaymentProxyWithParameters.java index 75b4cdcd7d..caa161971e 100644 --- a/src/main/java/alfio/controller/api/v2/model/PaymentProxyWithParameters.java +++ b/src/main/java/alfio/controller/api/v2/model/PaymentProxyWithParameters.java @@ -17,14 +17,17 @@ package alfio.controller.api.v2.model; import alfio.model.transaction.PaymentProxy; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Map; -@AllArgsConstructor @Getter public class PaymentProxyWithParameters { private final PaymentProxy paymentProxy; private final Map parameters; + + public PaymentProxyWithParameters(PaymentProxy paymentProxy, Map parameters) { + this.paymentProxy = paymentProxy; + this.parameters = parameters; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/PurchaseContextWithReservations.java b/src/main/java/alfio/controller/api/v2/model/PurchaseContextWithReservations.java index 9456804fd2..280252f647 100644 --- a/src/main/java/alfio/controller/api/v2/model/PurchaseContextWithReservations.java +++ b/src/main/java/alfio/controller/api/v2/model/PurchaseContextWithReservations.java @@ -19,8 +19,6 @@ import alfio.model.PurchaseContext; import alfio.model.ReservationWithPurchaseContext; import alfio.util.LocaleUtil; -import lombok.Getter; -import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.Validate; import java.time.ZonedDateTime; @@ -30,16 +28,11 @@ import java.util.Map; import java.util.stream.Collectors; -@RequiredArgsConstructor -@Getter -public class PurchaseContextWithReservations { - private final Map title; - private final String publicIdentifier; - private final PurchaseContext.PurchaseContextType type; - private final Map formattedStartDate; - private final Map formattedEndDate; - private final boolean sameDay; - private final List reservations; +public record PurchaseContextWithReservations(Map title, String publicIdentifier, + PurchaseContext.PurchaseContextType type, + Map formattedStartDate, + Map formattedEndDate, boolean sameDay, + List reservations) { public static PurchaseContextWithReservations from(List reservations, Map datePatternsMap) { diff --git a/src/main/java/alfio/controller/api/v2/model/ReservationHeader.java b/src/main/java/alfio/controller/api/v2/model/ReservationHeader.java index a599fa1882..51fa5864c6 100644 --- a/src/main/java/alfio/controller/api/v2/model/ReservationHeader.java +++ b/src/main/java/alfio/controller/api/v2/model/ReservationHeader.java @@ -20,7 +20,6 @@ import alfio.model.ReservationWithPurchaseContext; import alfio.model.TicketReservation; import lombok.Getter; -import lombok.RequiredArgsConstructor; import java.math.BigDecimal; import java.util.List; @@ -29,7 +28,6 @@ import static alfio.util.LocaleUtil.formatDate; -@RequiredArgsConstructor @Getter public class ReservationHeader { private final String id; @@ -44,6 +42,30 @@ public class ReservationHeader { private final PriceContainer.VatStatus vatStatus; private final List items; + public ReservationHeader(String id, + TicketReservation.TicketReservationStatus status, + Map formattedExpiresOn, + Map formattedConfirmedOn, + Map formattedCreatedOn, + String invoiceNumber, + BigDecimal finalPrice, + String currencyCode, + BigDecimal usedVatPercent, + PriceContainer.VatStatus vatStatus, + List items) { + this.id = id; + this.status = status; + this.formattedExpiresOn = formattedExpiresOn; + this.formattedConfirmedOn = formattedConfirmedOn; + this.formattedCreatedOn = formattedCreatedOn; + this.invoiceNumber = invoiceNumber; + this.finalPrice = finalPrice; + this.currencyCode = currencyCode; + this.usedVatPercent = usedVatPercent; + this.vatStatus = vatStatus; + this.items = items; + } + public static ReservationHeader from(ReservationWithPurchaseContext r, Map datePatternsMap) { return new ReservationHeader( diff --git a/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java b/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java index 89ac9f5387..126f9e9ca6 100644 --- a/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/ReservationInfo.java @@ -16,15 +16,17 @@ */ package alfio.controller.api.v2.model; +import alfio.controller.api.support.BookingInfoTicket; import alfio.model.BillingDetails; import alfio.model.OrderSummary; +import alfio.model.ReservationMetadata; import alfio.model.SummaryRow.SummaryType; import alfio.model.TicketCategory; import alfio.model.TicketReservation.TicketReservationStatus; +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; import alfio.model.subscription.UsageDetails; import alfio.model.transaction.PaymentMethod; import alfio.model.transaction.PaymentProxy; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.List; @@ -32,7 +34,6 @@ import java.util.UUID; import java.util.stream.Collectors; -@AllArgsConstructor @Getter public class ReservationInfo { private final String id; @@ -77,129 +78,67 @@ public class ReservationInfo { private final List subscriptionInfos; - - @AllArgsConstructor - @Getter - public static class TicketsByTicketCategory { - private final String name; - private final TicketCategory.TicketAccessType ticketAccessType; - private final List tickets; - } - - - @AllArgsConstructor - public static class BookingInfoTicket { - private final String uuid; - private final String firstName; - private final String lastName; - private final String email; - private final String fullName; - private final String userLanguage; - private final boolean assigned; - private final boolean locked; - private final boolean acquired; - private final boolean cancellationEnabled; - private final boolean sendMailEnabled; - private final boolean downloadEnabled; - private final List ticketFieldConfiguration; - private final Map formattedOnlineCheckInDate; - private final boolean onlineEventStarted; - - public String getEmail() { - return email; - } - - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } - - public String getUuid() { - return uuid; - } - - public String getFullName() { - return fullName; - } - - public boolean isAssigned() { - return assigned; - } - - public boolean isAcquired() { - return acquired; - } - - public String getUserLanguage() { - return userLanguage; - } - - public boolean isLocked() { return locked; } - - public boolean isCancellationEnabled() { - return cancellationEnabled; - } - - public List getTicketFieldConfigurationBeforeStandard() { - return ticketFieldConfiguration.stream().filter(AdditionalField::isBeforeStandardFields).collect(Collectors.toList()); - } - - public List getTicketFieldConfigurationAfterStandard() { - return ticketFieldConfiguration.stream().filter(tv -> !tv.isBeforeStandardFields()).collect(Collectors.toList()); - } - - public Map getFormattedOnlineCheckInDate() { - return formattedOnlineCheckInDate; - } - - public boolean isOnlineEventStarted() { - return onlineEventStarted; - } - - public boolean isSendMailEnabled() { - return sendMailEnabled; - } - - public boolean isDownloadEnabled() { - return downloadEnabled; - } + private final ReservationMetadata metadata; + + public ReservationInfo(String id, + String shortId, + String firstName, + String lastName, + String email, + long validity, + List ticketsByCategory, + ReservationInfoOrderSummary orderSummary, + TicketReservationStatus status, + boolean validatedBookingInformation, + Map formattedExpirationDate, + String invoiceNumber, + boolean invoiceRequested, + boolean invoiceOrReceiptDocumentPresent, + boolean paid, + boolean tokenAcquired, + PaymentProxy paymentProxy, + Boolean addCompanyBillingDetails, + String customerReference, + Boolean skipVatNr, + String billingAddress, + BillingDetails billingDetails, + boolean containsCategoriesLinkedToGroups, + Map activePaymentMethods, + List subscriptionInfos, + ReservationMetadata reservationMetadata) { + this.id = id; + this.shortId = shortId; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.validity = validity; + this.ticketsByCategory = ticketsByCategory; + this.orderSummary = orderSummary; + this.status = status; + this.validatedBookingInformation = validatedBookingInformation; + this.formattedExpirationDate = formattedExpirationDate; + this.invoiceNumber = invoiceNumber; + this.invoiceRequested = invoiceRequested; + this.invoiceOrReceiptDocumentPresent = invoiceOrReceiptDocumentPresent; + this.paid = paid; + this.tokenAcquired = tokenAcquired; + this.paymentProxy = paymentProxy; + this.addCompanyBillingDetails = addCompanyBillingDetails; + this.customerReference = customerReference; + this.skipVatNr = skipVatNr; + this.billingAddress = billingAddress; + this.billingDetails = billingDetails; + this.containsCategoriesLinkedToGroups = containsCategoriesLinkedToGroups; + this.activePaymentMethods = activePaymentMethods; + this.subscriptionInfos = subscriptionInfos; + this.metadata = reservationMetadata; } - @AllArgsConstructor - @Getter - public static class AdditionalField { - private final String name; - private final String value; - private final String type; - private final boolean required; - private final boolean editable; - private final Integer minLength; - private final Integer maxLength; - private final List restrictedValues; - private final List fields; - private final boolean beforeStandardFields; - private final Map description; - } - @AllArgsConstructor - @Getter - public static class Description { - private final String label; - private final String placeholder; - private final Map restrictedValuesDescription; - } - - @AllArgsConstructor - @Getter - public static class Field { - private final int fieldIndex; - private final String fieldValue; + public record TicketsByTicketCategory(String name, TicketCategory.TicketAccessType ticketAccessType, + List tickets) { } - @Getter public static class ReservationInfoOrderSummary { @@ -216,7 +155,7 @@ public static class ReservationInfoOrderSummary { public ReservationInfoOrderSummary(OrderSummary orderSummary) { this.summary = orderSummary.getSummary() .stream() - .map(s -> new ReservationInfoOrderSummaryRow(s.getName(), s.getAmount(), s.getPrice(), s.getSubTotal(), s.getType(), s.getTaxPercentage())) + .map(s -> new ReservationInfoOrderSummaryRow(s.name(), s.amount(), s.price(), s.subTotal(), s.type(), s.taxPercentage())) .collect(Collectors.toList()); this.totalPrice = orderSummary.getTotalPrice(); this.free = orderSummary.getFree(); @@ -229,32 +168,22 @@ public ReservationInfoOrderSummary(OrderSummary orderSummary) { } } - @AllArgsConstructor - @Getter - public static class ReservationInfoOrderSummaryRow { - private final String name; - private final int amount; - private final String price; - private final String subTotal; - private final SummaryType type; - private final String taxPercentage; + + + public record ReservationInfoOrderSummaryRow(String name, + int amount, + String price, + String subTotal, + SummaryType type, + String taxPercentage) { } - @AllArgsConstructor - @Getter - public static class SubscriptionInfo { - private final UUID id; - private final String pin; - private final UsageDetails usageDetails; - private final SubscriptionOwner owner; + + public record SubscriptionInfo(UUID id, String pin, UsageDetails usageDetails, SubscriptionOwner owner, SubscriptionConfiguration configuration) { } - @AllArgsConstructor - @Getter - public static class SubscriptionOwner { - private final String firstName; - private final String lastName; - private final String email; + + public record SubscriptionOwner(String firstName, String lastName, String email) { } } diff --git a/src/main/java/alfio/controller/api/v2/model/ReservationPaymentResult.java b/src/main/java/alfio/controller/api/v2/model/ReservationPaymentResult.java index 44830c1f3a..4b72af99bc 100644 --- a/src/main/java/alfio/controller/api/v2/model/ReservationPaymentResult.java +++ b/src/main/java/alfio/controller/api/v2/model/ReservationPaymentResult.java @@ -16,10 +16,8 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class ReservationPaymentResult { private final boolean success; @@ -27,4 +25,12 @@ public class ReservationPaymentResult { private final String redirectUrl; private final boolean failure; private final String gatewayIdOrNull; + + public ReservationPaymentResult(boolean success, boolean redirect, String redirectUrl, boolean failure, String gatewayIdOrNull) { + this.success = success; + this.redirect = redirect; + this.redirectUrl = redirectUrl; + this.failure = failure; + this.gatewayIdOrNull = gatewayIdOrNull; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/ReservationStatusInfo.java b/src/main/java/alfio/controller/api/v2/model/ReservationStatusInfo.java index 4d462ef6a2..aa4ac9b848 100644 --- a/src/main/java/alfio/controller/api/v2/model/ReservationStatusInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/ReservationStatusInfo.java @@ -17,13 +17,16 @@ package alfio.controller.api.v2.model; import alfio.model.TicketReservation; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class ReservationStatusInfo { private final TicketReservation.TicketReservationStatus status; private final boolean validatedBookingInformation; + + public ReservationStatusInfo(TicketReservation.TicketReservationStatus status, boolean validatedBookingInformation) { + this.status = status; + this.validatedBookingInformation = validatedBookingInformation; + } } diff --git a/src/main/java/alfio/controller/api/v2/model/SubscriptionDescriptorWithAdditionalInfo.java b/src/main/java/alfio/controller/api/v2/model/SubscriptionDescriptorWithAdditionalInfo.java index 1aaef04be6..8843f382a1 100644 --- a/src/main/java/alfio/controller/api/v2/model/SubscriptionDescriptorWithAdditionalInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/SubscriptionDescriptorWithAdditionalInfo.java @@ -22,17 +22,16 @@ import alfio.model.subscription.SubscriptionDescriptor; import alfio.util.MonetaryUtil; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import java.util.List; import java.util.Map; -@AllArgsConstructor public class SubscriptionDescriptorWithAdditionalInfo implements ApiPurchaseContext { private final SubscriptionDescriptor subscriptionDescriptor; private final InvoicingConfiguration invoicingConfiguration; private final AnalyticsConfiguration analyticsConfiguration; private final EventWithAdditionalInfo.CaptchaConfiguration captchaConfiguration; + private final EmbeddingConfiguration embeddingConfiguration; //payment related information private final String bankAccount; @@ -50,6 +49,40 @@ public class SubscriptionDescriptorWithAdditionalInfo implements ApiPurchaseCont private final Map formattedValidTo; private final Integer numAvailable; + public SubscriptionDescriptorWithAdditionalInfo(SubscriptionDescriptor subscriptionDescriptor, + InvoicingConfiguration invoicingConfiguration, + AnalyticsConfiguration analyticsConfiguration, + EventWithAdditionalInfo.CaptchaConfiguration captchaConfiguration, + EmbeddingConfiguration embeddingConfiguration, + String bankAccount, + List bankAccountOwner, + String organizationEmail, + String organizationName, + DatesWithTimeZoneOffset salePeriod, + Map formattedOnSaleFrom, + Map formattedOnSaleTo, + String timeZone, + Map formattedValidFrom, + Map formattedValidTo, + Integer numAvailable) { + this.subscriptionDescriptor = subscriptionDescriptor; + this.invoicingConfiguration = invoicingConfiguration; + this.analyticsConfiguration = analyticsConfiguration; + this.captchaConfiguration = captchaConfiguration; + this.embeddingConfiguration = embeddingConfiguration; + this.bankAccount = bankAccount; + this.bankAccountOwner = bankAccountOwner; + this.organizationEmail = organizationEmail; + this.organizationName = organizationName; + this.salePeriod = salePeriod; + this.formattedOnSaleFrom = formattedOnSaleFrom; + this.formattedOnSaleTo = formattedOnSaleTo; + this.timeZone = timeZone; + this.formattedValidFrom = formattedValidFrom; + this.formattedValidTo = formattedValidTo; + this.numAvailable = numAvailable; + } + @Override public InvoicingConfiguration getInvoicingConfiguration() { return invoicingConfiguration; @@ -187,6 +220,17 @@ public Integer getMaxEntries() { return subscriptionDescriptor.getMaxEntries() > 0 ? subscriptionDescriptor.getMaxEntries() : null; } + @Override + public OfflinePaymentConfiguration getOfflinePaymentConfiguration() { + // offline payment is not supported for subscriptions + return null; + } + + @Override + public EmbeddingConfiguration getEmbeddingConfiguration() { + return embeddingConfiguration; + } + @Override public boolean isCanApplySubscriptions() { return false;//cannot buy a subscription with another subscription diff --git a/src/main/java/alfio/controller/api/v2/model/TicketCategory.java b/src/main/java/alfio/controller/api/v2/model/TicketCategory.java index 6f63f9bb1a..8ef45d5fff 100644 --- a/src/main/java/alfio/controller/api/v2/model/TicketCategory.java +++ b/src/main/java/alfio/controller/api/v2/model/TicketCategory.java @@ -49,13 +49,15 @@ public class TicketCategory { private final boolean accessRestricted; private final boolean soldOutOrLimitReached; private final Integer availableTickets; + private final boolean displayTaxInformation; // public TicketCategory(SaleableTicketCategory saleableTicketCategory, Map description, Map formattedInception, Map formattedExpiration, - boolean displayTicketsLeft) { + boolean displayTicketsLeft, + boolean displayTaxInformation) { this.description = description; this.id = saleableTicketCategory.getId(); @@ -82,5 +84,7 @@ public TicketCategory(SaleableTicketCategory saleableTicketCategory, // this.availableTickets = displayTicketsLeft && saleableTicketCategory.isBounded() ? saleableTicketCategory.getAvailableTickets() : null; this.ordinal = saleableTicketCategory.isAccessRestricted() ? -1 : saleableTicketCategory.getOrdinal(); + + this.displayTaxInformation = displayTaxInformation; } } diff --git a/src/main/java/alfio/controller/api/v2/model/TicketInfo.java b/src/main/java/alfio/controller/api/v2/model/TicketInfo.java index d3142a52a2..538765c182 100644 --- a/src/main/java/alfio/controller/api/v2/model/TicketInfo.java +++ b/src/main/java/alfio/controller/api/v2/model/TicketInfo.java @@ -16,13 +16,11 @@ */ package alfio.controller.api.v2.model; -import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Map; @Getter -@AllArgsConstructor public class TicketInfo implements DateValidity { private final String fullName; @@ -43,5 +41,35 @@ public class TicketInfo implements DateValidity { private final Map formattedBeginTime; //the hour/minute component private final Map formattedEndDate; private final Map formattedEndTime; + + public TicketInfo(String fullName, + String email, + String uuid, + String ticketCategoryName, + String reservationFullName, + String reservationId, + boolean deskPaymentRequired, + String timeZone, + DatesWithTimeZoneOffset datesWithOffset, + boolean sameDay, + Map formattedBeginDate, + Map formattedBeginTime, + Map formattedEndDate, + Map formattedEndTime) { + this.fullName = fullName; + this.email = email; + this.uuid = uuid; + this.ticketCategoryName = ticketCategoryName; + this.reservationFullName = reservationFullName; + this.reservationId = reservationId; + this.deskPaymentRequired = deskPaymentRequired; + this.timeZone = timeZone; + this.datesWithOffset = datesWithOffset; + this.sameDay = sameDay; + this.formattedBeginDate = formattedBeginDate; + this.formattedBeginTime = formattedBeginTime; + this.formattedEndDate = formattedEndDate; + this.formattedEndTime = formattedEndTime; + } // } diff --git a/src/main/java/alfio/controller/api/v2/model/WalletConfiguration.java b/src/main/java/alfio/controller/api/v2/model/WalletConfiguration.java new file mode 100644 index 0000000000..cff3423839 --- /dev/null +++ b/src/main/java/alfio/controller/api/v2/model/WalletConfiguration.java @@ -0,0 +1,35 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.v2.model; + +public class WalletConfiguration { + private final boolean gWalletEnabled; + private final boolean passEnabled; + + public WalletConfiguration(boolean gWalletEnabled, boolean passEnabled) { + this.gWalletEnabled = gWalletEnabled; + this.passEnabled = passEnabled; + } + + public boolean isgWalletEnabled() { + return gWalletEnabled; + } + + public boolean isPassEnabled() { + return passEnabled; + } +} diff --git a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java index 9b1f018593..cd213224b0 100644 --- a/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/EventApiV2Controller.java @@ -38,7 +38,6 @@ import alfio.model.system.ConfigurationKeys; import alfio.repository.*; import alfio.util.*; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; @@ -69,15 +68,14 @@ @RestController @RequestMapping("/api/v2/public/") -@AllArgsConstructor public class EventApiV2Controller { + private static final String TICKET_CATEGORY_DATE_FORMAT = "common.ticket-category.date-format"; private final EventManager eventManager; private final EventRepository eventRepository; private final ConfigurationManager configurationManager; private final EventDescriptionRepository eventDescriptionRepository; private final TicketCategoryDescriptionRepository ticketCategoryDescriptionRepository; - private final PaymentManager paymentManager; private final MessageSourceManager messageSourceManager; private final AdditionalServiceRepository additionalServiceRepository; private final AdditionalServiceTextRepository additionalServiceTextRepository; @@ -94,6 +92,48 @@ public class EventApiV2Controller { private final ExtensionManager extensionManager; private final ClockProvider clockProvider; + public EventApiV2Controller(EventManager eventManager, + EventRepository eventRepository, + ConfigurationManager configurationManager, + EventDescriptionRepository eventDescriptionRepository, + TicketCategoryDescriptionRepository ticketCategoryDescriptionRepository, + MessageSourceManager messageSourceManager, + AdditionalServiceRepository additionalServiceRepository, + AdditionalServiceTextRepository additionalServiceTextRepository, + WaitingQueueManager waitingQueueManager, + I18nManager i18nManager, + TicketCategoryRepository ticketCategoryRepository, + TicketRepository ticketRepository, + TicketReservationManager ticketReservationManager, + PromoCodeDiscountRepository promoCodeRepository, + EventStatisticsManager eventStatisticsManager, + RecaptchaService recaptchaService, + PromoCodeRequestManager promoCodeRequestManager, + EventLoader eventLoader, + ExtensionManager extensionManager, + ClockProvider clockProvider) { + this.eventManager = eventManager; + this.eventRepository = eventRepository; + this.configurationManager = configurationManager; + this.eventDescriptionRepository = eventDescriptionRepository; + this.ticketCategoryDescriptionRepository = ticketCategoryDescriptionRepository; + this.messageSourceManager = messageSourceManager; + this.additionalServiceRepository = additionalServiceRepository; + this.additionalServiceTextRepository = additionalServiceTextRepository; + this.waitingQueueManager = waitingQueueManager; + this.i18nManager = i18nManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketRepository = ticketRepository; + this.ticketReservationManager = ticketReservationManager; + this.promoCodeRepository = promoCodeRepository; + this.eventStatisticsManager = eventStatisticsManager; + this.recaptchaService = recaptchaService; + this.promoCodeRequestManager = promoCodeRequestManager; + this.eventLoader = eventLoader; + this.extensionManager = extensionManager; + this.clockProvider = clockProvider; + } + @GetMapping("events") public ResponseEntity> listEvents(SearchOptions searchOptions) { @@ -108,9 +148,9 @@ public ResponseEntity> listEvents(SearchOptions searchOptio return new BasicEventInfo(e.getShortName(), e.getFileBlobId(), e.getTitle(), e.getFormat(), e.getLocation(), e.getTimeZone(), DatesWithTimeZoneOffset.fromEvent(e), e.getSameDay(), formattedDates.beginDate, formattedDates.beginTime, formattedDates.endDate, formattedDates.endTime, - e.getContentLanguages().stream().map(cl -> new Language(cl.getLocale().getLanguage(), cl.getDisplayLanguage())).collect(toList())); + e.getContentLanguages().stream().map(cl -> new Language(cl.getLocale().getLanguage(), cl.getDisplayLanguage())).toList()); }) - .collect(Collectors.toList()); + .toList(); return new ResponseEntity<>(events, getCorsHeaders(), HttpStatus.OK); } @@ -158,8 +198,8 @@ public ResponseEntity getTicketCategories(@PathVariable("eventN var ticketCategories = ticketCategoryRepository.findAllTicketCategories(event.getId()); List saleableTicketCategories = ticketCategories.stream() - .filter((c) -> !c.isAccessRestricted() || shouldDisplayRestrictedCategory(specialCode, c, promoCodeDiscount)) - .map((category) -> { + .filter(c -> !c.isAccessRestricted() || shouldDisplayRestrictedCategory(specialCode, c, promoCodeDiscount)) + .map(category -> { int maxTickets = getMaxAmountOfTicketsPerReservation(configurations, ticketCategoryLevelConfiguration, category.getId()); PromoCodeDiscount filteredPromoCode = promoCodeDiscount.filter(promoCode -> shouldApplyDiscount(promoCode, category)).orElse(null); if (specialCode.isPresent()) { @@ -171,23 +211,24 @@ public ResponseEntity getTicketCategories(@PathVariable("eventN now, event, ticketReservationManager.countAvailableTickets(event, category), maxTickets, filteredPromoCode); }) - .collect(Collectors.toList()); + .toList(); - var valid = saleableTicketCategories.stream().filter(tc -> !tc.getExpired()).collect(Collectors.toList()); + var valid = saleableTicketCategories.stream().filter(tc -> !tc.getExpired()).toList(); // - var ticketCategoryIds = valid.stream().map(SaleableTicketCategory::getId).collect(Collectors.toList()); + var ticketCategoryIds = valid.stream().map(SaleableTicketCategory::getId).toList(); var ticketCategoryDescriptions = ticketCategoryDescriptionRepository.descriptionsByTicketCategory(ticketCategoryIds); + var categoriesNoTax = configurationManager.getCategoriesWithNoTaxes(ticketCategoryIds); boolean displayTicketsLeft = configurations.get(DISPLAY_TICKETS_LEFT_INDICATOR).getValueAsBooleanOrDefault(); var categoriesByExpiredFlag = saleableTicketCategories.stream() .map(stc -> { - var description = Formatters.applyCommonMark(ticketCategoryDescriptions.getOrDefault(stc.getId(), Collections.emptyMap())); - var expiration = Formatters.getFormattedDate(event, stc.getZonedExpiration(), "common.ticket-category.date-format", messageSource); - var inception = Formatters.getFormattedDate(event, stc.getZonedInception(), "common.ticket-category.date-format", messageSource); - return new TicketCategory(stc, description, inception, expiration, displayTicketsLeft && !stc.isAccessRestricted()); + var description = Formatters.applyCommonMark(ticketCategoryDescriptions.getOrDefault(stc.getId(), Collections.emptyMap()), messageSource); + var expiration = Formatters.getFormattedDate(event, stc.getZonedExpiration(), TICKET_CATEGORY_DATE_FORMAT, messageSource); + var inception = Formatters.getFormattedDate(event, stc.getZonedInception(), TICKET_CATEGORY_DATE_FORMAT, messageSource); + return new TicketCategory(stc, description, inception, expiration, displayTicketsLeft && !stc.isAccessRestricted(), !categoriesNoTax.contains(stc.getId())); }) .sorted(Comparator.comparingInt(TicketCategory::getOrdinal)) .collect(partitioningBy(TicketCategory::isExpired)); @@ -201,33 +242,32 @@ public ResponseEntity getTicketCategories(@PathVariable("eventN var saleableAdditionalServices = additionalServiceRepository.loadAllForEvent(event.getId()) .stream() .map(as -> new SaleableAdditionalService(event, as, promoCode.orElse(null))) - .filter(SaleableAdditionalService::isNotExpired) - .collect(Collectors.toList()); + .filter(SaleableAdditionalService::isNotExpired).toList(); // will be used for fetching descriptions and titles for all the languages - var saleableAdditionalServicesIds = saleableAdditionalServices.stream().map(SaleableAdditionalService::getId).collect(Collectors.toList()); + var saleableAdditionalServicesIds = saleableAdditionalServices.stream().map(SaleableAdditionalService::getId).toList(); var additionalServiceTexts = additionalServiceTextRepository.getDescriptionsByAdditionalServiceIds(saleableAdditionalServicesIds); var additionalServicesRes = saleableAdditionalServices.stream().map(as -> { - var expiration = Formatters.getFormattedDate(event, as.getZonedExpiration(), "common.ticket-category.date-format", messageSource); - var inception = Formatters.getFormattedDate(event, as.getZonedInception(), "common.ticket-category.date-format", messageSource); + var expiration = Formatters.getFormattedDate(event, as.getZonedExpiration(), TICKET_CATEGORY_DATE_FORMAT, messageSource); + var inception = Formatters.getFormattedDate(event, as.getZonedInception(), TICKET_CATEGORY_DATE_FORMAT, messageSource); var title = additionalServiceTexts.getOrDefault(as.getId(), Collections.emptyMap()).getOrDefault(AdditionalServiceText.TextType.TITLE, Collections.emptyMap()); - var description = Formatters.applyCommonMark(additionalServiceTexts.getOrDefault(as.getId(), Collections.emptyMap()).getOrDefault(AdditionalServiceText.TextType.DESCRIPTION, Collections.emptyMap())); + var description = Formatters.applyCommonMark(additionalServiceTexts.getOrDefault(as.getId(), Collections.emptyMap()).getOrDefault(AdditionalServiceText.TextType.DESCRIPTION, Collections.emptyMap()), messageSource); return new AdditionalService(as.getId(), as.getType(), as.getSupplementPolicy(), as.isFixPrice(), as.getAvailableQuantity(), as.getMaxQtyPerOrder(), as.getFree(), as.getFormattedFinalPrice(), as.getSupportsDiscount(), as.getDiscountedPrice(), as.getVatApplies(), as.getVatIncluded(), as.getVatPercentage().toString(), as.isExpired(), as.getSaleInFuture(), inception, expiration, title, description); - }).collect(Collectors.toList()); + }).toList(); // // waiting queue parameters boolean displayWaitingQueueForm = EventUtil.displayWaitingQueueForm(event, saleableTicketCategories, configurationManager, eventStatisticsManager.noSeatsAvailable()); boolean preSales = EventUtil.isPreSales(event, saleableTicketCategories); Predicate waitingQueueTargetCategory = tc -> !tc.getExpired() && !tc.isBounded(); - List unboundedCategories = saleableTicketCategories.stream().filter(waitingQueueTargetCategory).collect(Collectors.toList()); - var tcForWaitingList = unboundedCategories.stream().map(stc -> new ItemsByCategory.TicketCategoryForWaitingList(stc.getId(), stc.getName())).collect(toList()); + List unboundedCategories = saleableTicketCategories.stream().filter(waitingQueueTargetCategory).toList(); + var tcForWaitingList = unboundedCategories.stream().map(stc -> new ItemsByCategory.TicketCategoryForWaitingList(stc.getId(), stc.getName())).toList(); // var activeCategories = categoriesByExpiredFlag.get(false); var expiredCategories = configurations.get(DISPLAY_EXPIRED_CATEGORIES).getValueAsBooleanOrDefault() ? categoriesByExpiredFlag.get(true) : List.of(); @@ -378,7 +418,7 @@ public ResponseEntity checkDiscount(@PathVariable("eventName") return new DynamicDiscount(formattedDiscount, d.getDiscountType(), formatDynamicCodeMessage(event, d)); }); }) - .filter(d -> d.getDiscountType() != PromoCodeDiscount.DiscountType.NONE) + .filter(d -> d.discountType() != PromoCodeDiscount.DiscountType.NONE) .map(ResponseEntity::ok) .orElseGet(() -> ResponseEntity.noContent().build()); } @@ -443,21 +483,20 @@ private Map formatDynamicCodeMessage(Event event, PromoCodeDisco Map res = new HashMap<>(); String code; String amount; - switch(promoCodeDiscount.getDiscountType()) { - case PERCENTAGE: + switch (promoCodeDiscount.getDiscountType()) { + case PERCENTAGE -> { code = "reservation.dynamic.discount.confirmation.percentage.message"; amount = String.valueOf(promoCodeDiscount.getDiscountAmount()); - break; - case FIXED_AMOUNT: + } + case FIXED_AMOUNT -> { amount = event.getCurrency() + " " + MonetaryUtil.formatCents(promoCodeDiscount.getDiscountAmount(), event.getCurrency()); code = "reservation.dynamic.discount.confirmation.fix-per-ticket.message"; - break; - case FIXED_AMOUNT_RESERVATION: + } + case FIXED_AMOUNT_RESERVATION -> { amount = event.getCurrency() + " " + MonetaryUtil.formatCents(promoCodeDiscount.getDiscountAmount(), event.getCurrency()); code = "reservation.dynamic.discount.confirmation.fix-per-reservation.message"; - break; - default: - throw new IllegalStateException("Unexpected discount code type"); + } + default -> throw new IllegalStateException("Unexpected discount code type"); } for (ContentLanguage cl : event.getContentLanguages()) { diff --git a/src/main/java/alfio/controller/api/v2/user/PollApiController.java b/src/main/java/alfio/controller/api/v2/user/PollApiController.java index 684d12e6b8..ecb50beb54 100644 --- a/src/main/java/alfio/controller/api/v2/user/PollApiController.java +++ b/src/main/java/alfio/controller/api/v2/user/PollApiController.java @@ -21,7 +21,6 @@ import alfio.manager.support.response.ValidatedResponse; import alfio.model.poll.Poll; import alfio.model.poll.PollWithOptions; -import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -30,11 +29,14 @@ @RestController @RequestMapping("/api/v2/public/event/{eventName}/poll") -@RequiredArgsConstructor public class PollApiController { private final PollManager pollManager; + public PollApiController(PollManager pollManager) { + this.pollManager = pollManager; + } + @GetMapping("") ResponseEntity>> getAll(@PathVariable("eventName") String eventName, @RequestParam("pin") String pin) { var result = pollManager.getActiveForEvent(eventName, pin); diff --git a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java index fdf7f9129e..b5a578b198 100644 --- a/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/ReservationApiV2Controller.java @@ -16,13 +16,13 @@ */ package alfio.controller.api.v2.user; +import alfio.controller.api.support.BookingInfoTicketLoader; import alfio.controller.api.support.TicketHelper; import alfio.controller.api.v2.model.PaymentProxyWithParameters; import alfio.controller.api.v2.model.ReservationInfo; import alfio.controller.api.v2.model.ReservationInfo.TicketsByTicketCategory; import alfio.controller.api.v2.model.ReservationPaymentResult; import alfio.controller.api.v2.model.ReservationStatusInfo; -import alfio.controller.api.v2.user.support.BookingInfoTicketLoader; import alfio.controller.api.v2.user.support.ReservationAccessDenied; import alfio.controller.form.ContactAndTicketsForm; import alfio.controller.form.PaymentForm; @@ -39,26 +39,23 @@ import alfio.manager.user.PublicUserManager; import alfio.model.*; import alfio.model.PurchaseContext.PurchaseContextType; -import alfio.model.subscription.Subscription; -import alfio.model.subscription.SubscriptionUsageExceeded; -import alfio.model.subscription.SubscriptionUsageExceededForEvent; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.subscription.UsageDetails; import alfio.model.system.ConfigurationKeys; import alfio.model.transaction.*; import alfio.repository.*; import alfio.util.*; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; -import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; @@ -76,14 +73,15 @@ import static alfio.model.system.ConfigurationKeys.ENABLE_ITALY_E_INVOICING; import static alfio.model.system.ConfigurationKeys.FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION; +import static java.util.Objects.requireNonNullElseGet; import static java.util.stream.Collectors.toMap; @RestController -@AllArgsConstructor @RequestMapping("/api/v2/public/") -@Log4j2 public class ReservationApiV2Controller { + private static final Logger log = LoggerFactory.getLogger(ReservationApiV2Controller.class); + private final EventManager eventManager; private final EventRepository eventRepository; private final TicketReservationManager ticketReservationManager; @@ -105,6 +103,53 @@ public class ReservationApiV2Controller { private final TicketRepository ticketRepository; private final PublicUserManager publicUserManager; private final ReverseChargeManager reverseChargeManager; + private final TicketCategoryRepository ticketCategoryRepository; + + public ReservationApiV2Controller(EventManager eventManager, + EventRepository eventRepository, + TicketReservationManager ticketReservationManager, + TicketReservationRepository ticketReservationRepository, + TicketFieldRepository ticketFieldRepository, + MessageSourceManager messageSourceManager, + ConfigurationManager configurationManager, + PaymentManager paymentManager, + FileUploadManager fileUploadManager, + TemplateManager templateManager, + ExtensionManager extensionManager, + TicketHelper ticketHelper, + EuVatChecker vatChecker, + RecaptchaService recaptchaService, + BookingInfoTicketLoader bookingInfoTicketLoader, + BillingDocumentManager billingDocumentManager, + PurchaseContextManager purchaseContextManager, + SubscriptionRepository subscriptionRepository, + TicketRepository ticketRepository, + PublicUserManager publicUserManager, + ReverseChargeManager reverseChargeManager, + TicketCategoryRepository ticketCategoryRepository) { + this.eventManager = eventManager; + this.eventRepository = eventRepository; + this.ticketReservationManager = ticketReservationManager; + this.ticketReservationRepository = ticketReservationRepository; + this.ticketFieldRepository = ticketFieldRepository; + this.messageSourceManager = messageSourceManager; + this.configurationManager = configurationManager; + this.paymentManager = paymentManager; + this.fileUploadManager = fileUploadManager; + this.templateManager = templateManager; + this.extensionManager = extensionManager; + this.ticketHelper = ticketHelper; + this.vatChecker = vatChecker; + this.recaptchaService = recaptchaService; + this.bookingInfoTicketLoader = bookingInfoTicketLoader; + this.billingDocumentManager = billingDocumentManager; + this.purchaseContextManager = purchaseContextManager; + this.subscriptionRepository = subscriptionRepository; + this.ticketRepository = ticketRepository; + this.publicUserManager = publicUserManager; + this.reverseChargeManager = reverseChargeManager; + this.ticketCategoryRepository = ticketCategoryRepository; + } /** * Note: now it will return for any states of the reservation. @@ -163,10 +208,7 @@ public ResponseEntity getReservationInfo(@PathVariable("reserva var additionalInfo = ticketReservationRepository.getAdditionalInfo(reservationId); - var shortReservationId = ticketReservationManager.getShortReservationID(purchaseContext, reservation); - var italianInvoicing = additionalInfo.getInvoicingAdditionalInfo().getItalianEInvoicing() == null ? - new TicketReservationInvoicingAdditionalInfo.ItalianEInvoicing(null, null, null, null, false) : - additionalInfo.getInvoicingAdditionalInfo().getItalianEInvoicing(); + var shortReservationId = configurationManager.getShortReservationID(purchaseContext, reservation); // @@ -182,14 +224,16 @@ public ResponseEntity getReservationInfo(@PathVariable("reserva List subscriptionInfos = null; if (purchaseContext.ofType(PurchaseContextType.subscription)) { subscriptionInfos = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream() - .limit(1) // since we support only one subscription for now, it make sense to limit the result to avoid N+1 + .limit(1) // since we support only one subscription for now, it makes sense to limit the result to avoid N+1 .map(s -> { int usageCount = ticketRepository.countSubscriptionUsage(s.getId(), null); + var metadata = requireNonNullElseGet(subscriptionRepository.getSubscriptionMetadata(s.getId()), SubscriptionMetadata::empty); return new ReservationInfo.SubscriptionInfo( s.getStatus() == AllocationStatus.ACQUIRED ? s.getId() : null, s.getStatus() == AllocationStatus.ACQUIRED ? s.getPin() : null, UsageDetails.fromSubscription(s, usageCount), - new ReservationInfo.SubscriptionOwner(s.getFirstName(), s.getLastName(), s.getEmail())); + new ReservationInfo.SubscriptionOwner(s.getFirstName(), s.getLastName(), s.getEmail()), + metadata.getConfiguration()); }) .collect(Collectors.toList()); } @@ -215,7 +259,8 @@ public ResponseEntity getReservationInfo(@PathVariable("reserva // containsCategoriesLinkedToGroups, getActivePaymentMethods(purchaseContext, ticketsByCategory.keySet(), orderSummary, reservationId), - subscriptionInfos + subscriptionInfos, + ticketReservationRepository.getMetadata(reservationId) )); })); @@ -299,7 +344,7 @@ public ResponseEntity> confirmOvervi return buildReservationPaymentStatus(bindingResult); } - if(isCaptchaInvalid(reservationCost.getPriceWithVAT(), paymentForm.getPaymentProxy(), paymentForm.getCaptcha(), request, event)) { + if(isCaptchaInvalid(reservationCost.priceWithVAT(), paymentForm.getPaymentProxy(), paymentForm.getCaptcha(), request, event)) { log.debug("captcha validation failed."); bindingResult.reject(ErrorsCode.STEP_2_CAPTCHA_VALIDATION_FAILED); } @@ -321,7 +366,7 @@ public ResponseEntity> confirmOvervi paymentToken = paymentManager.buildPaymentToken(paymentForm.getGatewayToken(), paymentForm.getPaymentProxy(), new PaymentContext(event, reservationId)); } - PaymentSpecification spec = new PaymentSpecification(reservationId, paymentToken, reservationCost.getPriceWithVAT(), + PaymentSpecification spec = new PaymentSpecification(reservationId, paymentToken, reservationCost.priceWithVAT(), event, reservation.getEmail(), customerName, reservation.getBillingAddress(), reservation.getCustomerReference(), locale, reservation.isInvoiceRequested(), !reservation.isDirectAssignmentRequested(), orderSummary, reservation.getVatCountryCode(), reservation.getVatNr(), reservation.getVatStatus(), @@ -384,10 +429,10 @@ public ResponseEntity> validateToOverview(@PathVariab boolean invoiceOnly = configurationManager.isInvoiceOnly(purchaseContext); - if(invoiceOnly && reservationCost.getPriceWithVAT() > 0) { + if(invoiceOnly && reservationCost.priceWithVAT() > 0) { //override, that's why we save it contactAndTicketsForm.setInvoiceRequested(true); - } else if (reservationCost.getPriceWithVAT() == 0) { + } else if (reservationCost.priceWithVAT() == 0) { contactAndTicketsForm.setInvoiceRequested(false); } @@ -395,10 +440,20 @@ public ResponseEntity> validateToOverview(@PathVariab ticketReservationRepository.resetVat(reservationId, contactAndTicketsForm.isInvoiceRequested(), purchaseContext.getVatStatus(), - reservation.getSrcPriceCts(), reservationCost.getPriceWithVAT(), reservationCost.getVAT(), Math.abs(reservationCost.getDiscount()), reservation.getCurrencyCode()); - if(contactAndTicketsForm.isBusiness()) { + reservation.getSrcPriceCts(), reservationCost.priceWithVAT(), reservationCost.VAT(), Math.abs(reservationCost.discount()), reservation.getCurrencyCode()); + + var optionalCustomTaxPolicy = extensionManager.handleCustomTaxPolicy(purchaseContext, reservationId, contactAndTicketsForm, reservationCost); + if (optionalCustomTaxPolicy.isPresent()) { + log.debug("Custom tax policy returned for reservation {}. Applying it.", reservationId); + reverseChargeManager.applyCustomTaxPolicy( + purchaseContext, + optionalCustomTaxPolicy.get(), + reservationId, + contactAndTicketsForm, + bindingResult); + } else if(reservationCost.priceWithVAT() > 0 && (contactAndTicketsForm.isBusiness() || configurationManager.noTaxesFlagDefinedFor(ticketCategoryRepository.findCategoriesInReservation(reservationId)))) { reverseChargeManager.checkAndApplyVATRules(purchaseContext, reservationId, contactAndTicketsForm, bindingResult); - } else if(reservationCost.getPriceWithVAT() > 0) { + } else if(reservationCost.priceWithVAT() > 0) { reverseChargeManager.resetVat(purchaseContext, reservationId); } diff --git a/src/main/java/alfio/controller/api/v2/user/SubscriptionsApiController.java b/src/main/java/alfio/controller/api/v2/user/SubscriptionsApiController.java index 8ae1e41153..6994614f40 100644 --- a/src/main/java/alfio/controller/api/v2/user/SubscriptionsApiController.java +++ b/src/main/java/alfio/controller/api/v2/user/SubscriptionsApiController.java @@ -32,7 +32,6 @@ import alfio.repository.user.OrganizationRepository; import alfio.util.ClockProvider; import alfio.util.MonetaryUtil; -import lombok.AllArgsConstructor; import org.joda.money.CurrencyUnit; import org.springframework.context.MessageSource; import org.springframework.http.HttpStatus; @@ -47,15 +46,14 @@ import java.util.stream.Collectors; import static alfio.model.PriceContainer.VatStatus.isVatIncluded; -import static alfio.model.system.ConfigurationKeys.BANK_ACCOUNT_NR; -import static alfio.model.system.ConfigurationKeys.BANK_ACCOUNT_OWNER; +import static alfio.model.system.ConfigurationKeys.*; import static java.util.stream.Collectors.toList; @RestController @RequestMapping("/api/v2/public/") -@AllArgsConstructor public class SubscriptionsApiController { + private static final String DATE_FORMAT_KEY = "common.event.date-format"; private final SubscriptionManager subscriptionManager; private final I18nManager i18nManager; private final TicketReservationManager reservationManager; @@ -64,11 +62,25 @@ public class SubscriptionsApiController { private final MessageSourceManager messageSourceManager; private final ClockProvider clockProvider; + public SubscriptionsApiController(SubscriptionManager subscriptionManager, + I18nManager i18nManager, + TicketReservationManager reservationManager, + ConfigurationManager configurationManager, + OrganizationRepository organizationRepository, + MessageSourceManager messageSourceManager, + ClockProvider clockProvider) { + this.subscriptionManager = subscriptionManager; + this.i18nManager = i18nManager; + this.reservationManager = reservationManager; + this.configurationManager = configurationManager; + this.organizationRepository = organizationRepository; + this.messageSourceManager = messageSourceManager; + this.clockProvider = clockProvider; + } + @GetMapping("subscriptions") public ResponseEntity> listSubscriptions(SearchOptions searchOptions) { - var contentLanguages = i18nManager.getAvailableLanguages(); - var now = ZonedDateTime.now(ClockProvider.clock()); var activeSubscriptions = subscriptionManager.getActivePublicSubscriptionsDescriptor(now, searchOptions) .stream() @@ -100,10 +112,10 @@ private static BasicSubscriptionDescriptorInfo subscriptionDescriptorMapper(Subs currencyDescriptor, s.getVat(), isVatIncluded(s.getVatStatus()), - Formatters.getFormattedDate(s, s.getOnSaleFrom(), "common.event.date-format", messageSource), - Formatters.getFormattedDate(s, s.getOnSaleTo(), "common.event.date-format", messageSource), - Formatters.getFormattedDate(s, s.getValidityFrom(), "common.event.date-format", messageSource), - Formatters.getFormattedDate(s, s.getValidityTo(), "common.event.date-format", messageSource), + Formatters.getFormattedDate(s, s.getOnSaleFrom(), DATE_FORMAT_KEY, messageSource), + Formatters.getFormattedDate(s, s.getOnSaleTo(), DATE_FORMAT_KEY, messageSource), + Formatters.getFormattedDate(s, s.getValidityFrom(), DATE_FORMAT_KEY, messageSource), + Formatters.getFormattedDate(s, s.getValidityTo(), DATE_FORMAT_KEY, messageSource), s.getContentLanguages().stream().map(cl -> new Language(cl.getLocale().getLanguage(), cl.getDisplayLanguage())).collect(toList()) ); } @@ -133,16 +145,17 @@ public ResponseEntity getSubscriptionI invoicingInfo, analyticsConf, captchaConf, + new EmbeddingConfiguration(configurationsValues.get(EMBED_POST_MESSAGE_ORIGIN).getValueOrNull()), bankAccount, bankAccountOwner, orgContact.getEmail(), orgContact.getName(), DatesWithTimeZoneOffset.fromDates(s.getOnSaleFrom(), s.getOnSaleTo()), - Formatters.getFormattedDate(s, s.getOnSaleFrom(), "common.event.date-format", messageSource), - Formatters.getFormattedDate(s, s.getOnSaleTo(), "common.event.date-format", messageSource), + Formatters.getFormattedDate(s, s.getOnSaleFrom(), DATE_FORMAT_KEY, messageSource), + Formatters.getFormattedDate(s, s.getOnSaleTo(), DATE_FORMAT_KEY, messageSource), s.getZoneId().toString(), - Formatters.getFormattedDate(s, s.getValidityFrom(), "common.event.date-format", messageSource), - Formatters.getFormattedDate(s, s.getValidityTo(), "common.event.date-format", messageSource), + Formatters.getFormattedDate(s, s.getValidityFrom(), DATE_FORMAT_KEY, messageSource), + Formatters.getFormattedDate(s, s.getValidityTo(), DATE_FORMAT_KEY, messageSource), available); }) .map(ResponseEntity::ok) diff --git a/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java index 72f0214499..21464c8bb4 100644 --- a/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/TicketApiV2Controller.java @@ -16,21 +16,19 @@ */ package alfio.controller.api.v2.user; +import alfio.controller.api.support.BookingInfoTicketLoader; import alfio.controller.api.support.TicketHelper; import alfio.controller.api.v2.model.DatesWithTimeZoneOffset; import alfio.controller.api.v2.model.OnlineCheckInInfo; import alfio.controller.api.v2.model.ReservationInfo; import alfio.controller.api.v2.model.TicketInfo; -import alfio.controller.api.v2.user.support.BookingInfoTicketLoader; import alfio.controller.form.UpdateTicketOwnerForm; import alfio.controller.support.Formatters; import alfio.controller.support.TemplateProcessor; -import alfio.manager.ExtensionManager; -import alfio.manager.FileUploadManager; -import alfio.manager.NotificationManager; -import alfio.manager.TicketReservationManager; +import alfio.manager.*; import alfio.manager.i18n.MessageSourceManager; import alfio.manager.support.response.ValidatedResponse; +import alfio.manager.system.ConfigurationManager; import alfio.model.*; import alfio.model.transaction.PaymentProxy; import alfio.model.user.Organization; @@ -40,7 +38,6 @@ import alfio.util.ImageUtil; import alfio.util.LocaleUtil; import alfio.util.TemplateManager; -import lombok.AllArgsConstructor; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpStatus; @@ -65,7 +62,6 @@ import static alfio.util.EventUtil.firstMatchingCallLink; @RestController -@AllArgsConstructor public class TicketApiV2Controller { private final TicketHelper ticketHelper; @@ -79,6 +75,36 @@ public class TicketApiV2Controller { private final NotificationManager notificationManager; private final BookingInfoTicketLoader bookingInfoTicketLoader; private final TicketRepository ticketRepository; + private final SubscriptionManager subscriptionManager; + private final ConfigurationManager configurationManager; + + public TicketApiV2Controller(TicketHelper ticketHelper, + TicketReservationManager ticketReservationManager, + TicketCategoryRepository ticketCategoryRepository, + MessageSourceManager messageSourceManager, + ExtensionManager extensionManager, + FileUploadManager fileUploadManager, + OrganizationRepository organizationRepository, + TemplateManager templateManager, + NotificationManager notificationManager, + BookingInfoTicketLoader bookingInfoTicketLoader, + TicketRepository ticketRepository, + SubscriptionManager subscriptionManager, + ConfigurationManager configurationManager) { + this.ticketHelper = ticketHelper; + this.ticketReservationManager = ticketReservationManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.messageSourceManager = messageSourceManager; + this.extensionManager = extensionManager; + this.fileUploadManager = fileUploadManager; + this.organizationRepository = organizationRepository; + this.templateManager = templateManager; + this.notificationManager = notificationManager; + this.bookingInfoTicketLoader = bookingInfoTicketLoader; + this.ticketRepository = ticketRepository; + this.subscriptionManager = subscriptionManager; + this.configurationManager = configurationManager; + } @GetMapping(value = { @@ -95,7 +121,7 @@ public void showQrCode(@PathVariable("eventName") String eventName, var event = oData.get().getLeft(); var ticket = oData.get().getRight(); - String qrCodeText = ticket.ticketCode(event.getPrivateKey()); + String qrCodeText = ticket.ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive()); response.setContentType("image/png"); @@ -121,12 +147,16 @@ public void generateTicketPdf(@PathVariable("eventName") String eventName, try (OutputStream os = response.getOutputStream()) { TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(ticket.getCategoryId(), event.getId()); Organization organization = organizationRepository.getById(event.getOrganizationId()); - String reservationID = ticketReservationManager.getShortReservationID(event, ticketReservation); + String reservationID = configurationManager.getShortReservationID(event, ticketReservation); var ticketWithMetadata = TicketWithMetadataAttributes.build(ticket, ticketRepository.getTicketMetadata(ticket.getId())); - TemplateProcessor.renderPDFTicket(LocaleUtil.getTicketLanguage(ticket, LocaleUtil.forLanguageTag(ticketReservation.getUserLanguage(), event)), event, ticketReservation, + var locale = LocaleUtil.getTicketLanguage(ticket, LocaleUtil.forLanguageTag(ticketReservation.getUserLanguage(), event)); + TemplateProcessor.renderPDFTicket( + locale, event, ticketReservation, ticketWithMetadata, ticketCategory, organization, templateManager, fileUploadManager, - reservationID, os, ticketHelper.buildRetrieveFieldValuesFunction(), extensionManager); + reservationID, os, ticketHelper.buildRetrieveFieldValuesFunction(), extensionManager, + TemplateProcessor.getSubscriptionDetailsModelForTicket(ticket, subscriptionManager::findDescriptorBySubscriptionId, locale) + ); } catch (IOException ioe) { throw new IllegalStateException(ioe); } @@ -230,7 +260,7 @@ public ResponseEntity getTicketInfo(@PathVariable("eventName") Strin ticket.getUuid(), ticketCategory.getName(), ticketReservation.getFullName(), - ticketReservationManager.getShortReservationID(event, ticketReservation), + configurationManager.getShortReservationID(event, ticketReservation), deskPaymentRequired, event.getTimeZone(), DatesWithTimeZoneOffset.fromEvent(event), @@ -284,7 +314,7 @@ public ResponseEntity getCheckInInfo(@PathVariable("eventName var ticket = info.getTicket(); var event = info.getEventWithCheckInInfo(); var messageSource = messageSourceManager.getMessageSourceFor(event.getOrganizationId(), event.getId()); - String ticketCode = ticket.ticketCode(event.getPrivateKey()); + String ticketCode = ticket.ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive()); if(MessageDigest.isEqual(DigestUtils.sha256Hex(ticketCode).getBytes(StandardCharsets.UTF_8), checkInCode.getBytes(StandardCharsets.UTF_8))) { var categoryConfiguration = info.getCategoryMetadata().getOnlineConfiguration(); var eventConfiguration = event.getMetadata().getOnlineConfiguration(); diff --git a/src/main/java/alfio/controller/api/v2/user/UserApiV2Controller.java b/src/main/java/alfio/controller/api/v2/user/UserApiV2Controller.java index fd3cf6f280..c41239aff8 100644 --- a/src/main/java/alfio/controller/api/v2/user/UserApiV2Controller.java +++ b/src/main/java/alfio/controller/api/v2/user/UserApiV2Controller.java @@ -31,7 +31,6 @@ import alfio.manager.user.PublicUserManager; import alfio.model.ContentLanguage; import alfio.util.ErrorsCode; -import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; @@ -46,7 +45,6 @@ @RestController @RequestMapping("/api/v2/public/user") -@RequiredArgsConstructor public class UserApiV2Controller { private final PublicUserManager publicUserManager; @@ -55,6 +53,18 @@ public class UserApiV2Controller { private final ExtensionManager extensionManager; private final MessageSourceManager messageSourceManager; + public UserApiV2Controller(PublicUserManager publicUserManager, + TicketReservationManager ticketReservationManager, + ConfigurationManager configurationManager, + ExtensionManager extensionManager, + MessageSourceManager messageSourceManager) { + this.publicUserManager = publicUserManager; + this.ticketReservationManager = ticketReservationManager; + this.configurationManager = configurationManager; + this.extensionManager = extensionManager; + this.messageSourceManager = messageSourceManager; + } + @GetMapping("/me") public ResponseEntity getUserIdentity(Authentication principal) { if(principal != null) { diff --git a/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java b/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java index 5fc2e85b9c..b3736037e5 100644 --- a/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java +++ b/src/main/java/alfio/controller/api/v2/user/support/EventLoader.java @@ -17,7 +17,9 @@ package alfio.controller.api.v2.user.support; import alfio.controller.api.v2.model.AnalyticsConfiguration; +import alfio.controller.api.v2.model.EmbeddingConfiguration; import alfio.controller.api.v2.model.EventWithAdditionalInfo; +import alfio.controller.api.v2.model.OfflinePaymentConfiguration; import alfio.controller.support.Formatters; import alfio.manager.i18n.MessageSourceManager; import alfio.manager.system.ConfigurationManager; @@ -26,7 +28,6 @@ import alfio.model.system.ConfigurationKeys; import alfio.repository.*; import alfio.repository.user.OrganizationRepository; -import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import javax.servlet.http.HttpSession; @@ -35,7 +36,6 @@ import static alfio.model.system.ConfigurationKeys.*; @Component -@AllArgsConstructor public class EventLoader { private final EventRepository eventRepository; @@ -48,6 +48,26 @@ public class EventLoader { private final PromoCodeDiscountRepository promoCodeRepository; private final SubscriptionRepository subscriptionRepository; + public EventLoader(EventRepository eventRepository, + MessageSourceManager messageSourceManager, + EventDescriptionRepository eventDescriptionRepository, + OrganizationRepository organizationRepository, + ConfigurationManager configurationManager, + TicketCategoryRepository ticketCategoryRepository, + TicketRepository ticketRepository, + PromoCodeDiscountRepository promoCodeRepository, + SubscriptionRepository subscriptionRepository) { + this.eventRepository = eventRepository; + this.messageSourceManager = messageSourceManager; + this.eventDescriptionRepository = eventDescriptionRepository; + this.organizationRepository = organizationRepository; + this.configurationManager = configurationManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketRepository = ticketRepository; + this.promoCodeRepository = promoCodeRepository; + this.subscriptionRepository = subscriptionRepository; + } + public Optional loadEventInfo(String eventName, HttpSession session) { return eventRepository.findOptionalByShortName(eventName).filter(e -> e.getStatus() != Event.Status.DISABLED)// .map(event -> { @@ -56,7 +76,7 @@ public Optional loadEventInfo(String eventName, HttpSes var messageSource = messageSourceAndOverride.getLeft(); var i18nOverride = messageSourceAndOverride.getRight(); - var descriptions = Formatters.applyCommonMark(eventDescriptionRepository.findDescriptionByEventIdAsMap(event.getId())); + var descriptions = Formatters.applyCommonMark(eventDescriptionRepository.findDescriptionByEventIdAsMap(event.getId()), messageSource); var organization = organizationRepository.getContactById(event.getOrganizationId()); @@ -108,11 +128,14 @@ public Optional loadEventInfo(String eventName, HttpSes var hasLinkedSubscription = subscriptionRepository.hasLinkedSubscription(event.getId()); + var offlinePaymentConfiguration = new OfflinePaymentConfiguration(configurationsValues.get(SHOW_ONLY_BASIC_INSTRUCTIONS).getValueAsBooleanOrDefault()); + return new EventWithAdditionalInfo(event, locationDescriptor.getMapUrl(), organization, descriptions, bankAccount, bankAccountOwner, formattedDates.beginDate, formattedDates.beginTime, formattedDates.endDate, formattedDates.endTime, - invoicingConf, captchaConf, assignmentConf, promoConf, analyticsConf, + invoicingConf, captchaConf, assignmentConf, promoConf, analyticsConf, offlinePaymentConfiguration, + new EmbeddingConfiguration(configurationsValues.get(EMBED_POST_MESSAGE_ORIGIN).getValueOrNull()), MessageSourceManager.convertPlaceholdersForEachLanguage(i18nOverride), availableTicketsCount, customCss, hasLinkedSubscription); }); } diff --git a/src/main/java/alfio/controller/api/v2/user/support/PurchaseContextInfoBuilder.java b/src/main/java/alfio/controller/api/v2/user/support/PurchaseContextInfoBuilder.java index 39cdfe8bcd..eb9481dbc1 100644 --- a/src/main/java/alfio/controller/api/v2/user/support/PurchaseContextInfoBuilder.java +++ b/src/main/java/alfio/controller/api/v2/user/support/PurchaseContextInfoBuilder.java @@ -31,6 +31,8 @@ public class PurchaseContextInfoBuilder { + private PurchaseContextInfoBuilder() {} + public static Map configurationsValues(PurchaseContext purchaseContext, ConfigurationManager configurationManager) { return configurationManager.getFor(List.of( MAPS_PROVIDER, @@ -58,6 +60,7 @@ public static Map co // INVOICE_ADDRESS, VAT_NR, + SHOW_ONLY_BASIC_INSTRUCTIONS, // required by EuVatChecker.reverseChargeEnabled ENABLE_EU_VAT_DIRECTIVE, COUNTRY_OF_BUSINESS, @@ -65,7 +68,8 @@ public static Map co ENABLE_REVERSE_CHARGE_ONLINE, DISPLAY_TICKETS_LEFT_INDICATOR, - EVENT_CUSTOM_CSS + EVENT_CUSTOM_CSS, + EMBED_POST_MESSAGE_ORIGIN ), purchaseContext.getConfigurationLevel()); } diff --git a/src/main/java/alfio/controller/api/wallet/GoogleWalletApiController.java b/src/main/java/alfio/controller/api/wallet/GoogleWalletApiController.java new file mode 100644 index 0000000000..8b618e1ba6 --- /dev/null +++ b/src/main/java/alfio/controller/api/wallet/GoogleWalletApiController.java @@ -0,0 +1,56 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.api.wallet; + +import alfio.manager.wallet.GoogleWalletManager; +import alfio.model.EventAndOrganizationId; +import alfio.model.Ticket; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Optional; + +@RestController +@RequestMapping("/api/wallet/event/{eventName}/v1") +@Log4j2 +@RequiredArgsConstructor +public class GoogleWalletApiController { + + private final GoogleWalletManager walletManager; + + @GetMapping("/version/passes/{uuid}") + public void walletPass(@PathVariable("eventName") String eventName, + @PathVariable("uuid") String serialNumber, + HttpServletResponse response) throws IOException { + Optional> validationResult = walletManager.validateTicket(eventName, serialNumber); + if (validationResult.isEmpty()) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + } else { + String walletUrl = walletManager.createAddToWalletUrl(validationResult.get().getRight(), validationResult.get().getLeft()); + response.sendRedirect(walletUrl); + } + } + +} diff --git a/src/main/java/alfio/controller/decorator/SaleableAdditionalService.java b/src/main/java/alfio/controller/decorator/SaleableAdditionalService.java index 94aa44c0ea..9034d9f709 100644 --- a/src/main/java/alfio/controller/decorator/SaleableAdditionalService.java +++ b/src/main/java/alfio/controller/decorator/SaleableAdditionalService.java @@ -115,17 +115,12 @@ public String getDiscountedPrice() { } public boolean getVatIncluded() { - switch (getVatType()) { - case INHERITED: - return event.isVatIncluded(); - case NONE: - case CUSTOM_EXCLUDED: - return false; - case CUSTOM_INCLUDED: - return true; - default: - return false; - } + return switch (getVatType()) { + case INHERITED -> event.isVatIncluded(); + case NONE, CUSTOM_EXCLUDED -> false; + case CUSTOM_INCLUDED -> true; + default -> false; + }; } public BigDecimal getVatPercentage() { diff --git a/src/main/java/alfio/controller/decorator/SaleableTicketCategory.java b/src/main/java/alfio/controller/decorator/SaleableTicketCategory.java index 7e7629afaf..6d3180ae08 100644 --- a/src/main/java/alfio/controller/decorator/SaleableTicketCategory.java +++ b/src/main/java/alfio/controller/decorator/SaleableTicketCategory.java @@ -22,6 +22,7 @@ import alfio.model.TicketCategory; import alfio.util.MonetaryUtil; import lombok.experimental.Delegate; +import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; import java.time.ZoneId; @@ -111,7 +112,10 @@ public VatStatus getVatStatus() { } public String getFormattedFinalPrice() { - return MonetaryUtil.formatUnit(getFinalPriceToDisplay(getFinalPrice().add(getAppliedDiscount()), getVAT(), getVatStatus()), getCurrencyCode()); + if (StringUtils.isNotEmpty(getCurrencyCode())) { + return MonetaryUtil.formatUnit(getFinalPriceToDisplay(getFinalPrice().add(getAppliedDiscount()), getVAT(), getVatStatus()), getCurrencyCode()); + } + return ""; } public int getMaxTicketsAfterConfiguration() { diff --git a/src/main/java/alfio/controller/form/PaymentForm.java b/src/main/java/alfio/controller/form/PaymentForm.java index acdbaa481d..599e7bea3d 100644 --- a/src/main/java/alfio/controller/form/PaymentForm.java +++ b/src/main/java/alfio/controller/form/PaymentForm.java @@ -46,7 +46,7 @@ public void validate(BindingResult bindingResult, PurchaseContext purchaseContex List allowedProxies = purchaseContext.getAllowedPaymentProxies(); Optional paymentProxyOptional = Optional.ofNullable(paymentProxy); - boolean priceGreaterThanZero = reservationCost.getPriceWithVAT() > 0; + boolean priceGreaterThanZero = reservationCost.priceWithVAT() > 0; boolean multipleProxies = allowedProxies.size() > 1; if (multipleProxies && priceGreaterThanZero && paymentProxyOptional.isEmpty()) { bindingResult.reject(ErrorsCode.STEP_2_MISSING_PAYMENT_METHOD); diff --git a/src/main/java/alfio/controller/form/ReservationCreate.java b/src/main/java/alfio/controller/form/ReservationCreate.java index 5565cab768..b4e3f55c7d 100644 --- a/src/main/java/alfio/controller/form/ReservationCreate.java +++ b/src/main/java/alfio/controller/form/ReservationCreate.java @@ -17,13 +17,13 @@ package alfio.controller.form; import alfio.model.modification.AdditionalServiceReservationModification; -import alfio.model.modification.TicketReservationModification; +import alfio.model.modification.ReservationRequest; import java.util.List; -public interface ReservationCreate { +public interface ReservationCreate { String getPromoCode(); - List getTickets(); + List getTickets(); List getAdditionalServices(); String getCaptcha(); } diff --git a/src/main/java/alfio/controller/form/ReservationForm.java b/src/main/java/alfio/controller/form/ReservationForm.java index ea165c9c24..b644ea2387 100644 --- a/src/main/java/alfio/controller/form/ReservationForm.java +++ b/src/main/java/alfio/controller/form/ReservationForm.java @@ -25,7 +25,7 @@ //step 1 : choose tickets @Data -public class ReservationForm implements Serializable, ReservationCreate { +public class ReservationForm implements Serializable, ReservationCreate { private String promoCode; private List reservation; diff --git a/src/main/java/alfio/controller/form/SearchOptions.java b/src/main/java/alfio/controller/form/SearchOptions.java index 78a39be6e1..747008674f 100644 --- a/src/main/java/alfio/controller/form/SearchOptions.java +++ b/src/main/java/alfio/controller/form/SearchOptions.java @@ -17,16 +17,19 @@ package alfio.controller.form; import lombok.Data; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; import java.util.UUID; @Data -@Log4j2 public class SearchOptions { + + private static final Logger log = LoggerFactory.getLogger(SearchOptions.class); + private String subscription; private Integer organizer; private String organizerSlug; diff --git a/src/main/java/alfio/controller/form/UpdateProfileForm.java b/src/main/java/alfio/controller/form/UpdateProfileForm.java index 34206aaaa4..da8a52cb12 100644 --- a/src/main/java/alfio/controller/form/UpdateProfileForm.java +++ b/src/main/java/alfio/controller/form/UpdateProfileForm.java @@ -16,18 +16,21 @@ */ package alfio.controller.form; -import lombok.Getter; -import lombok.Setter; - import java.io.Serializable; import java.util.Map; -@Getter -@Setter public class UpdateProfileForm extends ContactAndTicketsForm implements Serializable { private Map additionalInfo; public boolean hasAdditionalInfo() { return additionalInfo != null && !additionalInfo.isEmpty(); } + + public Map getAdditionalInfo() { + return additionalInfo; + } + + public void setAdditionalInfo(Map additionalInfo) { + this.additionalInfo = additionalInfo; + } } diff --git a/src/main/java/alfio/controller/payment/PayPalCallbackController.java b/src/main/java/alfio/controller/payment/PayPalCallbackController.java index 80d1dbdda8..4495e689db 100644 --- a/src/main/java/alfio/controller/payment/PayPalCallbackController.java +++ b/src/main/java/alfio/controller/payment/PayPalCallbackController.java @@ -22,7 +22,6 @@ import alfio.model.PurchaseContext; import alfio.model.TicketReservation; import alfio.model.transaction.token.PayPalToken; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -35,13 +34,20 @@ @Controller @RequestMapping("/{purchaseContextType}/{purchaseContextIdentifier}/reservation/{reservationId}/payment/paypal") -@RequiredArgsConstructor public class PayPalCallbackController { private final PurchaseContextManager purchaseContextManager; private final TicketReservationManager ticketReservationManager; private final PayPalManager payPalManager; + public PayPalCallbackController(PurchaseContextManager purchaseContextManager, + TicketReservationManager ticketReservationManager, + PayPalManager payPalManager) { + this.purchaseContextManager = purchaseContextManager; + this.ticketReservationManager = ticketReservationManager; + this.payPalManager = payPalManager; + } + @GetMapping("/confirm") public String payPalSuccess(@PathVariable("purchaseContextType") PurchaseContext.PurchaseContextType purchaseContextType, @PathVariable("purchaseContextIdentifier") String purchaseContextId, diff --git a/src/main/java/alfio/controller/payment/SaferpayCallbackController.java b/src/main/java/alfio/controller/payment/SaferpayCallbackController.java index 2583280bf9..0b2a4646d4 100644 --- a/src/main/java/alfio/controller/payment/SaferpayCallbackController.java +++ b/src/main/java/alfio/controller/payment/SaferpayCallbackController.java @@ -20,19 +20,23 @@ import alfio.manager.TicketReservationManager; import alfio.manager.payment.saferpay.PaymentPageInitializeRequestBuilder; import alfio.model.PurchaseContext; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.util.UriComponentsBuilder; @Controller -@RequiredArgsConstructor public class SaferpayCallbackController { private final TicketReservationManager ticketReservationManager; private final PurchaseContextManager purchaseContextManager; + public SaferpayCallbackController(TicketReservationManager ticketReservationManager, + PurchaseContextManager purchaseContextManager) { + this.ticketReservationManager = ticketReservationManager; + this.purchaseContextManager = purchaseContextManager; + } + @GetMapping(PaymentPageInitializeRequestBuilder.CANCEL_URL_TEMPLATE) public String saferpayCancel(@PathVariable("purchaseContextType") PurchaseContext.PurchaseContextType purchaseContextType, @PathVariable("purchaseContextIdentifier") String purchaseContextIdentifier, diff --git a/src/main/java/alfio/controller/payment/api/PaymentApiController.java b/src/main/java/alfio/controller/payment/api/PaymentApiController.java index 5aeb600f3f..66f9f2d661 100644 --- a/src/main/java/alfio/controller/payment/api/PaymentApiController.java +++ b/src/main/java/alfio/controller/payment/api/PaymentApiController.java @@ -24,7 +24,6 @@ import alfio.model.TicketReservation; import alfio.model.transaction.PaymentMethod; import alfio.model.transaction.TransactionInitializationToken; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.tuple.Pair; import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; @@ -33,13 +32,20 @@ import java.util.Optional; @RestController -@AllArgsConstructor public class PaymentApiController { private final PaymentManager paymentManager; private final TicketReservationManager ticketReservationManager; private final PurchaseContextManager purchaseContextManager; + public PaymentApiController(PaymentManager paymentManager, + TicketReservationManager ticketReservationManager, + PurchaseContextManager purchaseContextManager) { + this.paymentManager = paymentManager; + this.ticketReservationManager = ticketReservationManager; + this.purchaseContextManager = purchaseContextManager; + } + @PostMapping({"/api/reservation/{reservationId}/payment/{method}/init", "/api/events/{eventName}/reservation/{reservationId}/payment/{method}/init" //<-deprecated }) diff --git a/src/main/java/alfio/controller/payment/api/mollie/MolliePaymentWebhookController.java b/src/main/java/alfio/controller/payment/api/mollie/MolliePaymentWebhookController.java index 4e7f215981..5273cff3c1 100644 --- a/src/main/java/alfio/controller/payment/api/mollie/MolliePaymentWebhookController.java +++ b/src/main/java/alfio/controller/payment/api/mollie/MolliePaymentWebhookController.java @@ -20,9 +20,9 @@ import alfio.manager.TicketReservationManager; import alfio.model.transaction.PaymentContext; import alfio.model.transaction.PaymentProxy; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -36,12 +36,18 @@ import static alfio.manager.payment.MollieWebhookPaymentManager.*; @RestController -@Log4j2 -@AllArgsConstructor public class MolliePaymentWebhookController { + + private static final Logger log = LoggerFactory.getLogger(MolliePaymentWebhookController.class); + private final TicketReservationManager ticketReservationManager; private final PurchaseContextManager purchaseContextManager; + public MolliePaymentWebhookController(TicketReservationManager ticketReservationManager, PurchaseContextManager purchaseContextManager) { + this.ticketReservationManager = ticketReservationManager; + this.purchaseContextManager = purchaseContextManager; + } + @SuppressWarnings("MVCPathVariableInspection") @PostMapping(WEBHOOK_URL_TEMPLATE) public ResponseEntity receivePaymentConfirmation(HttpServletRequest request, diff --git a/src/main/java/alfio/controller/payment/api/saferpay/SaferpayPaymentWebhookController.java b/src/main/java/alfio/controller/payment/api/saferpay/SaferpayPaymentWebhookController.java index 8319ac40cd..950b52c7df 100644 --- a/src/main/java/alfio/controller/payment/api/saferpay/SaferpayPaymentWebhookController.java +++ b/src/main/java/alfio/controller/payment/api/saferpay/SaferpayPaymentWebhookController.java @@ -21,7 +21,6 @@ import alfio.manager.payment.saferpay.PaymentPageInitializeRequestBuilder; import alfio.model.transaction.PaymentContext; import alfio.model.transaction.PaymentProxy; -import lombok.AllArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -31,11 +30,16 @@ import java.util.Map; @RestController -@AllArgsConstructor public class SaferpayPaymentWebhookController { + private final TicketReservationManager ticketReservationManager; private final PurchaseContextManager purchaseContextManager; + public SaferpayPaymentWebhookController(TicketReservationManager ticketReservationManager, PurchaseContextManager purchaseContextManager) { + this.ticketReservationManager = ticketReservationManager; + this.purchaseContextManager = purchaseContextManager; + } + @GetMapping(PaymentPageInitializeRequestBuilder.WEBHOOK_URL_TEMPLATE) ResponseEntity handleTransactionNotification(@PathVariable("reservationId") String reservationId) { return purchaseContextManager.findByReservationId(reservationId) diff --git a/src/main/java/alfio/controller/payment/api/stripe/StripePaymentWebhookController.java b/src/main/java/alfio/controller/payment/api/stripe/StripePaymentWebhookController.java index 636ed650b3..fc9389300a 100644 --- a/src/main/java/alfio/controller/payment/api/stripe/StripePaymentWebhookController.java +++ b/src/main/java/alfio/controller/payment/api/stripe/StripePaymentWebhookController.java @@ -19,8 +19,7 @@ import alfio.manager.TicketReservationManager; import alfio.model.transaction.PaymentProxy; import alfio.util.RequestUtils; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -30,27 +29,39 @@ import javax.servlet.http.HttpServletRequest; import java.util.Map; +import static alfio.util.HttpUtils.APPLICATION_JSON_UTF8; + @RestController -@Log4j2 -@AllArgsConstructor public class StripePaymentWebhookController { private final TicketReservationManager ticketReservationManager; + public StripePaymentWebhookController(TicketReservationManager ticketReservationManager) { + this.ticketReservationManager = ticketReservationManager; + } + @PostMapping("/api/payment/webhook/stripe/payment") public ResponseEntity receivePaymentConfirmation(@RequestHeader(value = "Stripe-Signature") String stripeSignature, HttpServletRequest request) { + var httpHeaders = new HttpHeaders(); + httpHeaders.add(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_UTF8); return RequestUtils.readRequest(request) .map(content -> { var result = ticketReservationManager.processTransactionWebhook(content, stripeSignature, PaymentProxy.STRIPE, Map.of()); if(result.isSuccessful()) { - return ResponseEntity.ok("OK"); + return ResponseEntity.status(HttpStatus.OK) + .headers(httpHeaders) + .body("OK"); } else if(result.isError()) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result.getReason()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .headers(httpHeaders) + .body(result.getReason()); } - return ResponseEntity.ok(result.getReason()); + return ResponseEntity.status(HttpStatus.OK) + .headers(httpHeaders) + .body(result.getReason()); }) - .orElseGet(() -> ResponseEntity.badRequest().body("NOK")); + .orElseGet(() -> ResponseEntity.badRequest().headers(httpHeaders).body("Malformed request.")); } } diff --git a/src/main/java/alfio/controller/support/CSPConfigurer.java b/src/main/java/alfio/controller/support/CSPConfigurer.java new file mode 100644 index 0000000000..919b75e887 --- /dev/null +++ b/src/main/java/alfio/controller/support/CSPConfigurer.java @@ -0,0 +1,89 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.support; + +import alfio.manager.system.ConfigurationLevel; +import alfio.manager.system.ConfigurationManager; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletResponse; +import java.security.SecureRandom; +import java.util.List; + +import static alfio.model.system.ConfigurationKeys.*; +import static alfio.model.system.ConfigurationKeys.EMBED_ALLOWED_ORIGINS; + +@Component +public class CSPConfigurer { + + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + private final ConfigurationManager configurationManager; + + public CSPConfigurer(ConfigurationManager configurationManager) { + this.configurationManager = configurationManager; + } + + public String addCspHeader(HttpServletResponse response, boolean embeddingSupported) { + return addCspHeader(response, ConfigurationLevel.system(), embeddingSupported); + } + + public String addCspHeader(HttpServletResponse response, ConfigurationLevel configurationLevel, boolean embeddingSupported) { + + var nonce = getNonce(); + + String reportUri = ""; + + var conf = configurationManager.getFor(List.of(SECURITY_CSP_REPORT_ENABLED, SECURITY_CSP_REPORT_URI, EMBED_ALLOWED_ORIGINS), configurationLevel); + + boolean enabledReport = conf.get(SECURITY_CSP_REPORT_ENABLED).getValueAsBooleanOrDefault(); + if (enabledReport) { + reportUri = " report-uri " + conf.get(SECURITY_CSP_REPORT_URI).getValueOrDefault("/report-csp-violation"); + } + // + // https://csp.withgoogle.com/docs/strict-csp.html + // with base-uri set to 'self' + + var frameAncestors = "'none'"; + var allowedContainer = conf.get(EMBED_ALLOWED_ORIGINS).getValueOrNull(); + if (embeddingSupported && StringUtils.isNotBlank(allowedContainer)) { + var splitHosts = allowedContainer.split("[,\n]"); + frameAncestors = String.join(" ", splitHosts); + // IE11 + response.addHeader("X-Frame-Options", "ALLOW-FROM "+splitHosts[0]); + } else { + response.addHeader("X-Frame-Options", "DENY"); + } + + response.addHeader("Content-Security-Policy", "object-src 'none'; "+ + "script-src 'strict-dynamic' 'nonce-" + nonce + "' 'unsafe-inline' http: https: " + + "'unsafe-hashes' 'sha256-MhtPZXr7+LpJUY5qtMutB+qWfQtMaPccfe7QXtCcEYc='" // see https://github.com/angular/angular-cli/issues/20864#issuecomment-983672336 + +"; " + + "base-uri 'self'; " + + "frame-ancestors " + frameAncestors + "; " + + reportUri); + + return nonce; + } + + private static String getNonce() { + var nonce = new byte[16]; //128 bit = 16 bytes + SECURE_RANDOM.nextBytes(nonce); + return Hex.encodeHexString(nonce); + } +} diff --git a/src/main/java/alfio/controller/support/FormattedEventDates.java b/src/main/java/alfio/controller/support/FormattedEventDates.java index a60e85ec0d..3c7ba50df9 100644 --- a/src/main/java/alfio/controller/support/FormattedEventDates.java +++ b/src/main/java/alfio/controller/support/FormattedEventDates.java @@ -16,14 +16,21 @@ */ package alfio.controller.support; -import lombok.RequiredArgsConstructor; - import java.util.Map; -@RequiredArgsConstructor public class FormattedEventDates { public final Map beginDate; public final Map beginTime; public final Map endDate; public final Map endTime; + + public FormattedEventDates(Map beginDate, + Map beginTime, + Map endDate, + Map endTime) { + this.beginDate = beginDate; + this.beginTime = beginTime; + this.endDate = endDate; + this.endTime = endTime; + } } diff --git a/src/main/java/alfio/controller/support/Formatters.java b/src/main/java/alfio/controller/support/Formatters.java index a620236884..dafbd92e1d 100644 --- a/src/main/java/alfio/controller/support/Formatters.java +++ b/src/main/java/alfio/controller/support/Formatters.java @@ -20,21 +20,23 @@ import alfio.model.Event; import alfio.model.LocalizedContent; import alfio.util.MustacheCustomTag; -import lombok.experimental.UtilityClass; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; -@UtilityClass -@Log4j2 -public class Formatters { +public final class Formatters { + + private Formatters() { + } + + private static final Logger log = LoggerFactory.getLogger(Formatters.class); + + public static final String LINK_NEW_TAB_KEY = "link.new-tab"; public static Map getFormattedDate(LocalizedContent localizedContent, ZonedDateTime date, String code, MessageSource messageSource) { if(localizedContent != null && date != null) { @@ -79,13 +81,18 @@ public static FormattedEventDates getFormattedDates(Event e, MessageSource messa } public static Map applyCommonMark(Map in) { + return applyCommonMark(in, null); + } + + public static Map applyCommonMark(Map in, MessageSource messageSource) { if (in == null) { return Collections.emptyMap(); } var res = new HashMap(); in.forEach((k, v) -> { - res.put(k, MustacheCustomTag.renderToHtmlCommonmarkEscaped(v)); + var targetBlankMessage = messageSource != null ? messageSource.getMessage(LINK_NEW_TAB_KEY, null, Locale.forLanguageTag(k)) : null; + res.put(k, MustacheCustomTag.renderToHtmlCommonmarkEscaped(v, targetBlankMessage)); }); return res; } diff --git a/src/main/java/alfio/controller/support/TemplateProcessor.java b/src/main/java/alfio/controller/support/TemplateProcessor.java index 795584b917..defee0e086 100644 --- a/src/main/java/alfio/controller/support/TemplateProcessor.java +++ b/src/main/java/alfio/controller/support/TemplateProcessor.java @@ -20,6 +20,9 @@ import alfio.manager.FileUploadManager; import alfio.manager.support.PartialTicketTextGenerator; import alfio.model.*; +import alfio.model.metadata.SubscriptionMetadata; +import alfio.model.subscription.Subscription; +import alfio.model.subscription.SubscriptionDescriptor; import alfio.model.user.Organization; import alfio.util.EventUtil; import alfio.util.ImageUtil; @@ -32,21 +35,16 @@ import com.openhtmltopdf.pdfboxout.PdfBoxFontResolver; import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; -import lombok.extern.log4j.Log4j2; import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.pdmodel.PDDocument; import org.springframework.core.io.ClassPathResource; import java.io.*; import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; -@Log4j2 public final class TemplateProcessor { private TemplateProcessor() {} @@ -91,16 +89,48 @@ public static void renderPDFTicket(Locale language, String reservationID, OutputStream os, Function> retrieveFieldValues, - ExtensionManager extensionManager) throws IOException { + ExtensionManager extensionManager, + Map initialModel) throws IOException { Optional imageData = extractImageModel(event, fileUploadManager); List fields = retrieveFieldValues.apply(ticketWithMetadata.getTicket()); - Map model = TemplateResource.buildModelForTicketPDF(organization, event, ticketReservation, ticketCategory, ticketWithMetadata, imageData, reservationID, - fields.stream().collect(Collectors.toMap(TicketFieldConfigurationDescriptionAndValue::getName, TicketFieldConfigurationDescriptionAndValue::getValueDescription))); + var model = new HashMap<>(Objects.requireNonNullElse(initialModel, Map.of())); + model.putAll(TemplateResource.buildModelForTicketPDF(organization, event, ticketReservation, ticketCategory, ticketWithMetadata, imageData, reservationID, + fields.stream().collect(Collectors.toMap(TicketFieldConfigurationDescriptionAndValue::getName, TicketFieldConfigurationDescriptionAndValue::getValueDescription)))); String page = templateManager.renderTemplate(event, TemplateResource.TICKET_PDF, model, language).getTextPart(); renderToPdf(page, os, extensionManager, event); } + public static Map getSubscriptionDetailsModelForTicket(Ticket ticket, + Function subscriptionDescriptorLoader, + Locale locale) { + boolean hasSubscription = ticket.getSubscriptionId() != null; + var result = new HashMap(); + result.put("hasSubscription", hasSubscription); + if (hasSubscription) { + var subscriptionDescriptor = subscriptionDescriptorLoader.apply(ticket.getSubscriptionId()); + result.put("subscriptionTitle", subscriptionDescriptor.getLocalizedTitle(locale)); + } + return result; + } + + public static void renderSubscriptionPDF(Subscription subscription, + Locale locale, + SubscriptionDescriptor subscriptionDescriptor, + TicketReservation reservation, + SubscriptionMetadata metadata, + Organization organization, + TemplateManager templateManager, + FileUploadManager fileUploadManager, + String reservationId, + ByteArrayOutputStream os, + ExtensionManager extensionManager) throws IOException { + Optional imageData = extractImageModel(subscriptionDescriptor, fileUploadManager); + Map model = TemplateResource.buildModelForSubscriptionPDF(subscription, subscriptionDescriptor, organization, metadata, imageData, reservationId, locale, reservation); + String page = templateManager.renderTemplate(subscriptionDescriptor, TemplateResource.SUBSCRIPTION_PDF, model, locale).getTextPart(); + renderToPdf(page, os, extensionManager, subscriptionDescriptor); + } + public static void renderToPdf(String page, OutputStream os, ExtensionManager extensionManager, PurchaseContext purchaseContext) throws IOException { if(extensionManager.handlePdfTransformation(page, purchaseContext, os)) { @@ -113,6 +143,8 @@ public static void renderToPdf(String page, OutputStream os, ExtensionManager ex builder.useProtocolsStreamImplementation(new AlfioInternalFSStreamFactory(), "alfio-internal"); builder.useProtocolsStreamImplementation(new InvalidProtocolFSStreamFactory(), "http", "https", "file", "jar"); builder.useFastMode(); + builder.usePdfUaAccessbility(true); + builder.usePdfAConformance(PdfRendererBuilder.PdfAConformance.PDFA_3_U); var parser = new Parser(); @@ -195,24 +227,23 @@ public static boolean buildReceiptOrInvoicePdf(PurchaseContext purchaseContext, public static String renderReceiptOrInvoicePdfTemplate(PurchaseContext purchaseContext, FileUploadManager fileUploadManager, Locale language, TemplateManager templateManager, Map model, TemplateResource templateResource) { extractImageModel(purchaseContext, fileUploadManager).ifPresent(imageData -> { - model.put("eventImage", imageData.getEventImage()); - model.put("imageWidth", imageData.getImageWidth()); - model.put("imageHeight", imageData.getImageHeight()); + model.put("eventImage", imageData.eventImage()); + model.put("imageWidth", imageData.imageWidth()); + model.put("imageHeight", imageData.imageHeight()); }); return templateManager.renderTemplate(purchaseContext, templateResource, model, language).getTextPart(); } public static Optional buildBillingDocumentPdf(BillingDocument.Type documentType, PurchaseContext purchaseContext, FileUploadManager fileUploadManager, Locale language, TemplateManager templateManager, Map model, ExtensionManager extensionManager) { - switch (documentType) { - case INVOICE: - return buildInvoicePdf(purchaseContext, fileUploadManager, language, templateManager, model, extensionManager); - case RECEIPT: - return buildReceiptPdf(purchaseContext, fileUploadManager, language, templateManager, model, extensionManager); - case CREDIT_NOTE: - return buildCreditNotePdf(purchaseContext, fileUploadManager, language, templateManager, model, extensionManager); - default: - throw new IllegalStateException(documentType + " not supported"); - } + return switch (documentType) { + case INVOICE -> + buildInvoicePdf(purchaseContext, fileUploadManager, language, templateManager, model, extensionManager); + case RECEIPT -> + buildReceiptPdf(purchaseContext, fileUploadManager, language, templateManager, model, extensionManager); + case CREDIT_NOTE -> + buildCreditNotePdf(purchaseContext, fileUploadManager, language, templateManager, model, extensionManager); + default -> throw new IllegalStateException(documentType + " not supported"); + }; } private static Optional buildFrom(PurchaseContext purchaseContext, diff --git a/src/main/java/alfio/controller/support/UserStatus.java b/src/main/java/alfio/controller/support/UserStatus.java new file mode 100644 index 0000000000..78414f10fc --- /dev/null +++ b/src/main/java/alfio/controller/support/UserStatus.java @@ -0,0 +1,26 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.controller.support; + +public record UserStatus(boolean authenticated, + String username, + String alfioVersion, + boolean demoModeEnabled, + boolean devModeEnabled, + boolean prodModeEnabled) { + +} diff --git a/src/main/java/alfio/extension/ConsoleLogger.java b/src/main/java/alfio/extension/ConsoleLogger.java index 396b316438..8b05c1f470 100644 --- a/src/main/java/alfio/extension/ConsoleLogger.java +++ b/src/main/java/alfio/extension/ConsoleLogger.java @@ -16,13 +16,16 @@ */ package alfio.extension; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.stream.Stream; -@Slf4j public class ConsoleLogger { + + private static final Logger log = LoggerFactory.getLogger(ConsoleLogger.class); + private final ExtensionLogger extensionLogger; public ConsoleLogger(ExtensionLogger extensionLogger) { diff --git a/src/main/java/alfio/extension/Extension.java b/src/main/java/alfio/extension/Extension.java index af4a8d13d1..4e25b86815 100644 --- a/src/main/java/alfio/extension/Extension.java +++ b/src/main/java/alfio/extension/Extension.java @@ -18,9 +18,7 @@ package alfio.extension; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -@Getter public class Extension { private final String path; @@ -28,6 +26,22 @@ public class Extension { private final String script; private final boolean enabled; + public String getPath() { + return path; + } + + public String getName() { + return name; + } + + public String getScript() { + return script; + } + + public boolean isEnabled() { + return enabled; + } + public Extension(@JsonProperty("path") String path, @JsonProperty("name") String name, @JsonProperty("script") String script, diff --git a/src/main/java/alfio/extension/ExtensionService.java b/src/main/java/alfio/extension/ExtensionService.java index 0bf8497b75..8b2e4f8d4d 100644 --- a/src/main/java/alfio/extension/ExtensionService.java +++ b/src/main/java/alfio/extension/ExtensionService.java @@ -25,8 +25,6 @@ import alfio.model.user.Organization; import alfio.repository.ExtensionLogRepository; import alfio.repository.ExtensionRepository; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; @@ -48,12 +46,9 @@ import static alfio.extension.ScriptingExecutionService.EXTENSION_CONFIGURATION_PARAMETERS; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElse; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; @Service -@Log4j2 -@AllArgsConstructor public class ExtensionService { private static final String EVALUATE_RESULT = "res = GSON.fromJson(JSON.stringify(res), returnClass);"; @@ -63,6 +58,7 @@ public class ExtensionService { private static final String OUTPUT = "output"; private static final String EXECUTION_KEY = "executionKey"; private static final String EXTENSION_EVENT = "extensionEvent"; + private final ScriptingExecutionService scriptingExecutionService; private final ExtensionRepository extensionRepository; private final ExtensionLogRepository extensionLogRepository; @@ -70,8 +66,22 @@ public class ExtensionService { private final ExternalConfiguration externalConfiguration; private final NamedParameterJdbcTemplate jdbcTemplate; + public ExtensionService(ScriptingExecutionService scriptingExecutionService, + ExtensionRepository extensionRepository, + ExtensionLogRepository extensionLogRepository, + PlatformTransactionManager platformTransactionManager, + ExternalConfiguration externalConfiguration, + NamedParameterJdbcTemplate jdbcTemplate) { + this.scriptingExecutionService = scriptingExecutionService; + this.extensionRepository = extensionRepository; + this.extensionLogRepository = extensionLogRepository; + this.platformTransactionManager = platformTransactionManager; + this.externalConfiguration = externalConfiguration; + this.jdbcTemplate = jdbcTemplate; + } + + - @AllArgsConstructor private static final class ExtensionLoggerImpl implements ExtensionLogger { private final ExtensionLogRepository extensionLogRepository; @@ -80,6 +90,18 @@ private static final class ExtensionLoggerImpl implements ExtensionLogger { private final String path; private final String name; + private ExtensionLoggerImpl(ExtensionLogRepository extensionLogRepository, + PlatformTransactionManager platformTransactionManager, + String effectivePath, + String path, + String name) { + this.extensionLogRepository = extensionLogRepository; + this.platformTransactionManager = platformTransactionManager; + this.effectivePath = effectivePath; + this.path = path; + this.name = name; + } + @Override public void logWarning(String msg) { executeInNewTransaction(s -> extensionLogRepository.insert(effectivePath, path, name, msg, ExtensionLog.Type.WARNING)); @@ -158,7 +180,7 @@ public void createOrUpdate(String previousPath, String previousName, Extension s for (ExtensionMetadata.Field field : requireNonNullElse(parameters.getFields(), List.of())) { for (String level : parameters.getConfigurationLevels()) { int confFieldId = extensionRepository.registerExtensionConfigurationMetadata(extensionId, field.getName(), field.getDescription(), field.getType(), level, field.isRequired()).getKey(); - List filteredParam = extensionParameterKeyValue.stream().filter(kv -> field.getName().equals(kv.getName()) && level.equals(kv.getConfigurationLevel())).collect(toList()); + List filteredParam = extensionParameterKeyValue.stream().filter(kv -> field.getName().equals(kv.getName()) && level.equals(kv.getConfigurationLevel())).toList(); var parameterSources = filteredParam.stream() .map(kv -> new MapSqlParameterSource("ecmId", confFieldId) .addValue("confPath", kv.getConfigurationPath()) @@ -216,8 +238,7 @@ private void deleteAndInsertSetting(String level, String path, List toUpdate2 = (toUpdate == null ? Collections.emptyList() : toUpdate); List filtered = toUpdate2.stream() - .filter(f -> StringUtils.trimToNull(f.getValue()) != null) - .collect(toList()); + .filter(f -> StringUtils.trimToNull(f.getValue()) != null).toList(); var parameterSources = filtered.stream() .map(kv -> new MapSqlParameterSource("ecmId", kv.getId()) .addValue("confPath", path) diff --git a/src/main/java/alfio/extension/ExtensionUtils.java b/src/main/java/alfio/extension/ExtensionUtils.java index 584c6a523b..2c189d0169 100644 --- a/src/main/java/alfio/extension/ExtensionUtils.java +++ b/src/main/java/alfio/extension/ExtensionUtils.java @@ -18,8 +18,6 @@ import alfio.util.Json; import com.google.gson.*; -import lombok.experimental.UtilityClass; -import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.HmacAlgorithms; import org.apache.commons.codec.digest.HmacUtils; @@ -36,9 +34,10 @@ import java.util.*; import java.util.stream.Collectors; -@Log4j2 -@UtilityClass -public class ExtensionUtils { +public final class ExtensionUtils { + + private ExtensionUtils() { + } private static final Gson JSON_SERIALIZER = Json.GSON.newBuilder() .registerTypeAdapter(Double.class, new DoubleSerializer()) @@ -101,24 +100,22 @@ public static String convertToJson(Object o) { static Object unwrap(Object o) { if (o instanceof Scriptable) { - if (o instanceof NativeArray) { + if (o instanceof NativeArray na) { List res = new ArrayList<>(); - var na = (NativeArray) o; for (var a : na) { res.add(unwrap(a)); } return res; - } else if (o instanceof NativeJavaObject) { - return ((NativeJavaObject) o).unwrap(); - } else if (o instanceof NativeObject) { - var na = (NativeObject) o; + } else if (o instanceof NativeJavaObject njo) { + return njo.unwrap(); + } else if (o instanceof NativeObject no) { Map res = new LinkedHashMap<>(); - for (var kv : na.entrySet()) { + for (var kv : no.entrySet()) { res.put(kv.getKey(), unwrap(kv.getValue())); } return res; - } else if (o instanceof IdScriptableObject) { - return parseIdScriptableObject((IdScriptableObject) o); + } else if (o instanceof IdScriptableObject ids) { + return parseIdScriptableObject(ids); } } else if (o instanceof CharSequence) { return o.toString(); @@ -128,17 +125,13 @@ static Object unwrap(Object o) { private static Object parseIdScriptableObject(IdScriptableObject object) { var className = object.getClassName(); - switch (className) { - case "String": - return ScriptRuntime.toCharSequence(object); - case "Boolean": - return Context.jsToJava(object, Boolean.class); - case "Date": { - return Context.jsToJava(object, Date.class); - } - } - // better safe than sorry: we ignore all the unknown objects - return null; + return switch (className) { + case "String" -> ScriptRuntime.toCharSequence(object); + case "Boolean" -> Context.jsToJava(object, Boolean.class); + case "Date" -> Context.jsToJava(object, Date.class); + // better safe than sorry: we ignore all the unknown objects + default -> null; + }; } /** diff --git a/src/main/java/alfio/extension/JSErrorReporter.java b/src/main/java/alfio/extension/JSErrorReporter.java index aae5e6e666..76c01c3c31 100644 --- a/src/main/java/alfio/extension/JSErrorReporter.java +++ b/src/main/java/alfio/extension/JSErrorReporter.java @@ -17,9 +17,10 @@ package alfio.extension; -import lombok.extern.log4j.Log4j2; import org.mozilla.javascript.ErrorReporter; import org.mozilla.javascript.EvaluatorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -28,12 +29,13 @@ * * Implements ErrorReporter interface of Rhino and prints syntax errors in the JS script. */ -@Log4j2 public class JSErrorReporter implements ErrorReporter { + private static final Logger log = LoggerFactory.getLogger(JSErrorReporter.class); + @Override public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) { - log.warn("Warning : " + message); + log.warn("Warning : {}", message); } @Override @@ -43,7 +45,7 @@ public EvaluatorException runtimeError(String message, String sourceName, int li @Override public void error(String message, String sourceName, int line, String lineSource, int lineOffset) { - log.warn("Error : " + message); + log.warn("Error : {}", message); } } diff --git a/src/main/java/alfio/extension/JSNodeVisitor.java b/src/main/java/alfio/extension/JSNodeVisitor.java index 9a1b6d23ef..b45d2e445d 100644 --- a/src/main/java/alfio/extension/JSNodeVisitor.java +++ b/src/main/java/alfio/extension/JSNodeVisitor.java @@ -68,8 +68,8 @@ private void checkNode(AstNode node) { return; } // keep track of function calls - if (node instanceof FunctionCall) { - AstNode target = ((FunctionCall) node).getTarget(); + if (node instanceof FunctionCall functionCall) { + AstNode target = functionCall.getTarget(); if (!(target instanceof PropertyGet)) { Name name = (Name) target; // keep all function calls inside an ArrayList @@ -77,8 +77,8 @@ private void checkNode(AstNode node) { // go back in the script and find the parent i.e. the function in which this node is inside AstNode parentNode = node.getParent(); while (parentNode != null) { - if (parentNode instanceof FunctionNode) { - Name parentName = ((FunctionNode) parentNode).getFunctionName(); + if (parentNode instanceof FunctionNode functionNode) { + Name parentName = functionNode.getFunctionName(); String id = parentName.getIdentifier(); // when the function name is found, check if it was called from somewhere else // if this function is called from another place and it contains another function call, throw an exception @@ -95,16 +95,17 @@ private void checkNode(AstNode node) { || node instanceof DoLoop || node instanceof WithStatement || node instanceof LabeledStatement - || (node instanceof PropertyGet && ((PropertyGet) node).getRight().getString().equals("System")) - || (node instanceof PropertyGet && ((PropertyGet) node).getRight().getString().equals("getClass")) + || (node instanceof PropertyGet pg1 && pg1.getRight().getString().equals("System")) + || (node instanceof PropertyGet pg2 && pg2.getRight().getString().equals("getClass")) || (node instanceof Name && node.getString().equals("newInstance"))) { - throw new ScriptNotValidException("Script not valid. One or more of the following components have been detected: \n" + - "- while() Loop\n" + - "- with() Statement\n" + - "- a labeled statement\n" + - "- Access to java.lang.System\n" + - "- Access to Object.getClass()\n" + - "- Java reflection usage"); + throw new ScriptNotValidException(""" + Script not valid. One or more of the following components have been detected:\s + - while() Loop + - with() Statement + - a labeled statement + - Access to java.lang.System + - Access to Object.getClass() + - Java reflection usage"""); } } diff --git a/src/main/java/alfio/extension/JSON.java b/src/main/java/alfio/extension/JSON.java index e5eafae2c9..16c6f22213 100644 --- a/src/main/java/alfio/extension/JSON.java +++ b/src/main/java/alfio/extension/JSON.java @@ -18,15 +18,18 @@ import alfio.util.Json; import com.google.gson.reflect.TypeToken; -import lombok.experimental.UtilityClass; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.Type; import java.util.Map; -@UtilityClass -@Log4j2 -public class JSON { +public final class JSON { + + private JSON() { + } + + private static final Logger log = LoggerFactory.getLogger(JSON.class); private static final Type PARSE_RETURN_TYPE = new TypeToken>(){}.getType(); diff --git a/src/main/java/alfio/extension/JSSymbol.java b/src/main/java/alfio/extension/JSSymbol.java index 286d73d9ae..1dd0b1807c 100644 --- a/src/main/java/alfio/extension/JSSymbol.java +++ b/src/main/java/alfio/extension/JSSymbol.java @@ -17,18 +17,21 @@ package alfio.extension; +import org.mozilla.javascript.Token; +import org.mozilla.javascript.ast.AstNode; +import org.mozilla.javascript.ast.FunctionNode; +import org.mozilla.javascript.ast.Name; +import org.mozilla.javascript.ast.VariableInitializer; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.mozilla.javascript.Token; -import org.mozilla.javascript.ast.*; - /** * * @author Ram Kulkarni - * http://ramkulkarni.com/blog/parsing-javascript-code-using-mozilla-rhino/ + * (source) * * This class holds reference to AST node and child elements. */ @@ -40,8 +43,7 @@ class JSSymbol { public JSSymbol(AstNode node) { this.node = node; - if (node instanceof FunctionNode) { - FunctionNode funcNode = (FunctionNode)node; + if (node instanceof FunctionNode funcNode) { List args = funcNode.getParams(); if (args != null) { for (AstNode argNode : args) { @@ -59,8 +61,8 @@ public void addChild(JSSymbol child) { if (child.getType() == Token.VAR) { //check if it is already added AstNode childNode = child.getNode(); - if (childNode instanceof VariableInitializer) { - String varName = ((Name)((VariableInitializer) childNode).getTarget()).getIdentifier(); + if (childNode instanceof VariableInitializer variableInitializer) { + String varName = ((Name) variableInitializer.getTarget()).getIdentifier(); if (localVars.containsKey(varName)) { return; } @@ -75,7 +77,7 @@ public void addChild (AstNode node) { addChild(new JSSymbol(node)); } - public ArrayList getChildren() { + public List getChildren() { return new ArrayList<>(children); } diff --git a/src/main/java/alfio/extension/ScriptingExecutionService.java b/src/main/java/alfio/extension/ScriptingExecutionService.java index 5f291dbf65..5dab61c471 100644 --- a/src/main/java/alfio/extension/ScriptingExecutionService.java +++ b/src/main/java/alfio/extension/ScriptingExecutionService.java @@ -29,8 +29,9 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.RemovalCause; -import lombok.extern.log4j.Log4j2; import org.mozilla.javascript.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import java.net.ConnectException; @@ -54,9 +55,10 @@ // -organizationId-eventId @Service -@Log4j2 public class ScriptingExecutionService { + private static final Logger log = LoggerFactory.getLogger(ScriptingExecutionService.class); + public static final String EXTENSION_NAME = "extensionName"; public static final String EXTENSION_PATH = "path"; public static final String EXTENSION_PARAMS = "params"; @@ -71,8 +73,8 @@ public class ScriptingExecutionService { private final Cache asyncExecutors = Caffeine.newBuilder() .expireAfterAccess(Duration.ofHours(12)) .removalListener((String key, Executor value, RemovalCause cause) -> { - if (value instanceof ExecutorService) { - ((ExecutorService) value).shutdown(); + if (value instanceof ExecutorService executorService) { + executorService.shutdown(); } }) .build(); @@ -196,8 +198,7 @@ private T executeScriptFinally(String name, String script, Map NULL_REQUEST_BODY = Set.of("GET", "HEAD"); private final HttpClient httpClient; diff --git a/src/main/java/alfio/extension/SimpleHttpClientCachedResponse.java b/src/main/java/alfio/extension/SimpleHttpClientCachedResponse.java index 7cda8c9fe3..75cca9877a 100644 --- a/src/main/java/alfio/extension/SimpleHttpClientCachedResponse.java +++ b/src/main/java/alfio/extension/SimpleHttpClientCachedResponse.java @@ -16,17 +16,38 @@ */ package alfio.extension; -import lombok.AllArgsConstructor; -import lombok.Getter; - import java.util.List; import java.util.Map; -@Getter -@AllArgsConstructor public class SimpleHttpClientCachedResponse { private final boolean successful; private final int code; private final Map> headers; private final String tempFilePath; + + public boolean isSuccessful() { + return successful; + } + + public int getCode() { + return code; + } + + public Map> getHeaders() { + return headers; + } + + public String getTempFilePath() { + return tempFilePath; + } + + public SimpleHttpClientCachedResponse(boolean successful, + int code, + Map> headers, + String tempFilePath) { + this.successful = successful; + this.code = code; + this.headers = headers; + this.tempFilePath = tempFilePath; + } } diff --git a/src/main/java/alfio/extension/SimpleHttpClientResponse.java b/src/main/java/alfio/extension/SimpleHttpClientResponse.java index a4613dae9e..d8e72a20ff 100644 --- a/src/main/java/alfio/extension/SimpleHttpClientResponse.java +++ b/src/main/java/alfio/extension/SimpleHttpClientResponse.java @@ -18,20 +18,26 @@ import alfio.util.Json; import com.google.gson.JsonSyntaxException; -import lombok.AllArgsConstructor; -import lombok.Getter; import java.util.List; import java.util.Map; -@Getter -@AllArgsConstructor public class SimpleHttpClientResponse { private final boolean successful; private final int code; private final Map> headers; private final String body; + public SimpleHttpClientResponse(boolean successful, + int code, + Map> headers, + String body) { + this.successful = successful; + this.code = code; + this.headers = headers; + this.body = body; + } + public Object getJsonBody() { return tryParse(body, Object.class); @@ -45,6 +51,7 @@ public T getJsonBody(Class clazz) { return tryParse(body, clazz); } + private static T tryParse(String body, Class clazz) { try { return Json.GSON.fromJson(body, clazz); @@ -52,4 +59,20 @@ private static T tryParse(String body, Class clazz) { return null; } } + + public boolean isSuccessful() { + return successful; + } + + public int getCode() { + return code; + } + + public Map> getHeaders() { + return headers; + } + + public String getBody() { + return body; + } } diff --git a/src/main/java/alfio/extension/support/SandboxNativeJavaMap.java b/src/main/java/alfio/extension/support/SandboxNativeJavaMap.java index bbfe318056..ed40095c2b 100644 --- a/src/main/java/alfio/extension/support/SandboxNativeJavaMap.java +++ b/src/main/java/alfio/extension/support/SandboxNativeJavaMap.java @@ -37,6 +37,11 @@ public Object get(String name, Scriptable start) { throw new OutOfBoundariesException("Out of boundaries class use."); } + if (map.get(name) == null) { + // prevent NPE on Rhino when map has an explicit null value for a given key + return null; + } + return super.get(name, start); } } diff --git a/src/main/java/alfio/job/Jobs.java b/src/main/java/alfio/job/Jobs.java index de4cbbe490..4f8d581c00 100644 --- a/src/main/java/alfio/job/Jobs.java +++ b/src/main/java/alfio/job/Jobs.java @@ -20,10 +20,10 @@ import alfio.manager.*; import alfio.manager.system.AdminJobExecutor; import alfio.manager.system.AdminJobManager; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.Scheduled; @@ -41,10 +41,10 @@ @Component @DependsOn("migrator") @Profile("!" + Initializer.PROFILE_DISABLE_JOBS) -@AllArgsConstructor -@Log4j2 public class Jobs { + private static final Logger log = LoggerFactory.getLogger(Jobs.class); + private static final int ONE_MINUTE = 1000 * 60; private static final int THIRTY_SECONDS = 1000 * 30; @@ -60,6 +60,22 @@ public class Jobs { private final WaitingQueueSubscriptionProcessor waitingQueueSubscriptionProcessor; private final AdminJobManager adminJobManager; + public Jobs(AdminReservationRequestManager adminReservationRequestManager, + FileUploadManager fileUploadManager, + NotificationManager notificationManager, + SpecialPriceTokenGenerator specialPriceTokenGenerator, + TicketReservationManager ticketReservationManager, + WaitingQueueSubscriptionProcessor waitingQueueSubscriptionProcessor, + AdminJobManager adminJobManager) { + this.adminReservationRequestManager = adminReservationRequestManager; + this.fileUploadManager = fileUploadManager; + this.notificationManager = notificationManager; + this.specialPriceTokenGenerator = specialPriceTokenGenerator; + this.ticketReservationManager = ticketReservationManager; + this.waitingQueueSubscriptionProcessor = waitingQueueSubscriptionProcessor; + this.adminJobManager = adminJobManager; + } + //cron each minute: "0 0/1 * * * ?" diff --git a/src/main/java/alfio/job/executor/AssignTicketToSubscriberJobExecutor.java b/src/main/java/alfio/job/executor/AssignTicketToSubscriberJobExecutor.java index 6e41872664..58831e4a9f 100644 --- a/src/main/java/alfio/job/executor/AssignTicketToSubscriberJobExecutor.java +++ b/src/main/java/alfio/job/executor/AssignTicketToSubscriberJobExecutor.java @@ -30,7 +30,8 @@ import alfio.repository.SubscriptionRepository; import alfio.repository.TicketCategoryRepository; import alfio.util.ClockProvider; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.time.LocalDate; @@ -47,11 +48,13 @@ import static alfio.model.system.ConfigurationKeys.GENERATE_TICKETS_FOR_SUBSCRIPTIONS; @Component -@Log4j2 public class AssignTicketToSubscriberJobExecutor implements AdminJobExecutor { + private static final Logger log = LoggerFactory.getLogger(AssignTicketToSubscriberJobExecutor.class); + public static final String EVENT_ID = "eventId"; public static final String ORGANIZATION_ID = "organizationId"; + public static final String FORCE_GENERATION = "forceGeneration"; private final AdminReservationRequestManager requestManager; private final ConfigurationManager configurationManager; private final SubscriptionRepository subscriptionRepository; @@ -90,9 +93,10 @@ public String process(AdminJobSchedule schedule) { // - status = 'ACQUIRED' var subscriptionsByEvent = subscriptionRepository.loadAvailableSubscriptionsByEvent((Integer) metadata.get(EVENT_ID), (Integer) metadata.get(ORGANIZATION_ID)); if (!subscriptionsByEvent.isEmpty()) { + boolean forceGeneration = Boolean.TRUE.equals(metadata.get(FORCE_GENERATION)); eventRepository.findByIds(subscriptionsByEvent.keySet()).forEach(event -> { - // 2. for each event check if the flag is active - boolean generationEnabled = configurationManager.getFor(GENERATE_TICKETS_FOR_SUBSCRIPTIONS, event.getConfigurationLevel()) + // 2. for each event check if the flag is active, unless forceGeneration has been specified + boolean generationEnabled = forceGeneration || configurationManager.getFor(GENERATE_TICKETS_FOR_SUBSCRIPTIONS, event.getConfigurationLevel()) .getValueAsBooleanOrDefault(); if (generationEnabled) { var subscriptions = subscriptionsByEvent.get(event.getId()); diff --git a/src/main/java/alfio/job/executor/BillingDocumentJobExecutor.java b/src/main/java/alfio/job/executor/BillingDocumentJobExecutor.java index 5c075b00c6..267d3441f4 100644 --- a/src/main/java/alfio/job/executor/BillingDocumentJobExecutor.java +++ b/src/main/java/alfio/job/executor/BillingDocumentJobExecutor.java @@ -24,7 +24,6 @@ import alfio.repository.EventRepository; import alfio.repository.user.OrganizationRepository; import alfio.util.RenderedTemplate; -import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import java.util.EnumSet; @@ -35,7 +34,6 @@ import java.util.regex.Pattern; @Component -@AllArgsConstructor public class BillingDocumentJobExecutor implements AdminJobExecutor { private final BillingDocumentManager billingDocumentManager; @@ -44,6 +42,18 @@ public class BillingDocumentJobExecutor implements AdminJobExecutor { private final NotificationManager notificationManager; private final OrganizationRepository organizationRepository; + public BillingDocumentJobExecutor(BillingDocumentManager billingDocumentManager, + TicketReservationManager ticketReservationManager, + EventRepository eventRepository, + NotificationManager notificationManager, + OrganizationRepository organizationRepository) { + this.billingDocumentManager = billingDocumentManager; + this.ticketReservationManager = ticketReservationManager; + this.eventRepository = eventRepository; + this.notificationManager = notificationManager; + this.organizationRepository = organizationRepository; + } + @Override public Set getJobNames() { return EnumSet.of(JobName.REGENERATE_INVOICES); diff --git a/src/main/java/alfio/job/executor/ReservationJobExecutor.java b/src/main/java/alfio/job/executor/ReservationJobExecutor.java index 6ac5c48dec..a1c46fa1dc 100644 --- a/src/main/java/alfio/job/executor/ReservationJobExecutor.java +++ b/src/main/java/alfio/job/executor/ReservationJobExecutor.java @@ -19,7 +19,6 @@ import alfio.manager.TicketReservationManager; import alfio.manager.system.AdminJobExecutor; import alfio.model.system.AdminJobSchedule; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.util.EnumSet; @@ -28,11 +27,14 @@ import static alfio.manager.system.AdminJobExecutor.JobName.*; @Component -@RequiredArgsConstructor public class ReservationJobExecutor implements AdminJobExecutor { private final TicketReservationManager ticketReservationManager; + public ReservationJobExecutor(TicketReservationManager ticketReservationManager) { + this.ticketReservationManager = ticketReservationManager; + } + @Override public Set getJobNames() { return EnumSet.of( diff --git a/src/main/java/alfio/job/executor/RetryFailedExtensionJobExecutor.java b/src/main/java/alfio/job/executor/RetryFailedExtensionJobExecutor.java index a1ab5edaca..132740d71e 100644 --- a/src/main/java/alfio/job/executor/RetryFailedExtensionJobExecutor.java +++ b/src/main/java/alfio/job/executor/RetryFailedExtensionJobExecutor.java @@ -20,14 +20,17 @@ import alfio.extension.ScriptingExecutionService; import alfio.manager.system.AdminJobExecutor; import alfio.model.system.AdminJobSchedule; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.EnumSet; import java.util.Map; import java.util.Set; -@Slf4j public class RetryFailedExtensionJobExecutor implements AdminJobExecutor { + + private static final Logger log = LoggerFactory.getLogger(RetryFailedExtensionJobExecutor.class); + private final ExtensionService extensionService; public RetryFailedExtensionJobExecutor(ExtensionService extensionService) { diff --git a/src/main/java/alfio/job/executor/RetryFailedReservationConfirmationExecutor.java b/src/main/java/alfio/job/executor/RetryFailedReservationConfirmationExecutor.java new file mode 100644 index 0000000000..c2c72f8fbc --- /dev/null +++ b/src/main/java/alfio/job/executor/RetryFailedReservationConfirmationExecutor.java @@ -0,0 +1,51 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.job.executor; + +import alfio.manager.ReservationFinalizer; +import alfio.manager.support.RetryFinalizeReservation; +import alfio.manager.system.AdminJobExecutor; +import alfio.model.system.AdminJobSchedule; +import alfio.util.Json; + +import java.util.EnumSet; +import java.util.Set; + +public class RetryFailedReservationConfirmationExecutor implements AdminJobExecutor { + + private final ReservationFinalizer reservationFinalizer; + private final Json json; + + public RetryFailedReservationConfirmationExecutor(ReservationFinalizer reservationFinalizer, + Json json) { + this.reservationFinalizer = reservationFinalizer; + this.json = json; + } + + @Override + public Set getJobNames() { + return EnumSet.of(JobName.RETRY_RESERVATION_CONFIRMATION); + } + + @Override + public String process(AdminJobSchedule schedule) { + var metadata = schedule.getMetadata(); + var retryFinalizeReservation = (String) metadata.get("payload"); + reservationFinalizer.retryFinalizeReservation(json.fromJsonString(retryFinalizeReservation, RetryFinalizeReservation.class)); + return null; + } +} diff --git a/src/main/java/alfio/manager/AdditionalServiceManager.java b/src/main/java/alfio/manager/AdditionalServiceManager.java index b1bd77cfdd..35212f11f6 100644 --- a/src/main/java/alfio/manager/AdditionalServiceManager.java +++ b/src/main/java/alfio/manager/AdditionalServiceManager.java @@ -17,12 +17,12 @@ package alfio.manager; import alfio.model.AdditionalService; +import alfio.model.AdditionalServiceItem; import alfio.model.AdditionalServiceItemExport; import alfio.model.AdditionalServiceText; import alfio.repository.AdditionalServiceItemRepository; import alfio.repository.AdditionalServiceRepository; import alfio.repository.AdditionalServiceTextRepository; -import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -33,7 +33,6 @@ import java.util.Optional; @Component -@AllArgsConstructor @Transactional public class AdditionalServiceManager { @@ -41,6 +40,14 @@ public class AdditionalServiceManager { private final AdditionalServiceTextRepository additionalServiceTextRepository; private final AdditionalServiceItemRepository additionalServiceItemRepository; + public AdditionalServiceManager(AdditionalServiceRepository additionalServiceRepository, + AdditionalServiceTextRepository additionalServiceTextRepository, + AdditionalServiceItemRepository additionalServiceItemRepository) { + this.additionalServiceRepository = additionalServiceRepository; + this.additionalServiceTextRepository = additionalServiceTextRepository; + this.additionalServiceItemRepository = additionalServiceItemRepository; + } + public List loadAllForEvent(int eventId) { return additionalServiceRepository.loadAllForEvent(eventId); @@ -50,7 +57,7 @@ public List findAllTextByAdditionalServiceId(int addition return additionalServiceTextRepository.findAllByAdditionalServiceId(additionalServiceId); } - public Map countUsageForEvent(int eventId) { + public Map> countUsageForEvent(int eventId) { return additionalServiceRepository.getCount(eventId); } diff --git a/src/main/java/alfio/manager/AdminReservationManager.java b/src/main/java/alfio/manager/AdminReservationManager.java index cddbe36d5e..c4445e779b 100644 --- a/src/main/java/alfio/manager/AdminReservationManager.java +++ b/src/main/java/alfio/manager/AdminReservationManager.java @@ -20,6 +20,8 @@ import alfio.manager.i18n.MessageSourceManager; import alfio.manager.payment.PaymentSpecification; import alfio.manager.support.DuplicateReferenceException; +import alfio.manager.support.IncompatibleStateException; +import alfio.manager.support.reservation.ReservationEmailContentHelper; import alfio.manager.system.ReservationPriceCalculator; import alfio.model.*; import alfio.model.PurchaseContext.PurchaseContextType; @@ -42,13 +44,13 @@ import alfio.repository.*; import alfio.repository.user.UserRepository; import alfio.util.*; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; @@ -60,6 +62,7 @@ import org.springframework.transaction.support.TransactionTemplate; import org.springframework.util.Assert; import org.springframework.validation.MapBindingResult; +import org.springframework.validation.ObjectError; import java.math.BigDecimal; import java.util.*; @@ -79,17 +82,17 @@ import static alfio.util.Wrappers.optionally; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElse; import static java.util.stream.Collectors.*; import static org.apache.commons.lang3.StringUtils.firstNonBlank; import static org.apache.commons.lang3.StringUtils.trimToNull; @Component -@Log4j2 -@RequiredArgsConstructor public class AdminReservationManager { - private static final EnumSet UPDATE_INVOICE_STATUSES = EnumSet.of(TicketReservationStatus.OFFLINE_PAYMENT, TicketReservationStatus.PENDING); + private static final Logger log = LoggerFactory.getLogger(AdminReservationManager.class); + private static final ErrorCode ERROR_CANNOT_CANCEL_CHECKED_IN_TICKETS = ErrorCode.custom("remove-reservation.failed", "This reservation contains checked-in tickets. Unable to cancel it."); private final PurchaseContextManager purchaseContextManager; private final EventManager eventManager; @@ -117,6 +120,63 @@ public class AdminReservationManager { private final BillingDocumentManager billingDocumentManager; private final ClockProvider clockProvider; private final SubscriptionRepository subscriptionRepository; + private final ReservationEmailContentHelper reservationEmailContentHelper; + + public AdminReservationManager(PurchaseContextManager purchaseContextManager, + EventManager eventManager, + TicketReservationManager ticketReservationManager, + TicketCategoryRepository ticketCategoryRepository, + TicketRepository ticketRepository, + SpecialPriceRepository specialPriceRepository, + TicketReservationRepository ticketReservationRepository, + EventRepository eventRepository, + PlatformTransactionManager transactionManager, + SpecialPriceTokenGenerator specialPriceTokenGenerator, + TicketFieldRepository ticketFieldRepository, + PaymentManager paymentManager, + NotificationManager notificationManager, + MessageSourceManager messageSourceManager, + TemplateManager templateManager, + AdditionalServiceItemRepository additionalServiceItemRepository, + AuditingRepository auditingRepository, + UserRepository userRepository, + ExtensionManager extensionManager, + BillingDocumentRepository billingDocumentRepository, + FileUploadManager fileUploadManager, + PromoCodeDiscountRepository promoCodeDiscountRepository, + AdditionalServiceRepository additionalServiceRepository, + BillingDocumentManager billingDocumentManager, + ClockProvider clockProvider, + SubscriptionRepository subscriptionRepository, + ReservationEmailContentHelper reservationEmailContentHelper) { + this.purchaseContextManager = purchaseContextManager; + this.eventManager = eventManager; + this.ticketReservationManager = ticketReservationManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketRepository = ticketRepository; + this.specialPriceRepository = specialPriceRepository; + this.ticketReservationRepository = ticketReservationRepository; + this.eventRepository = eventRepository; + this.transactionManager = transactionManager; + this.specialPriceTokenGenerator = specialPriceTokenGenerator; + this.ticketFieldRepository = ticketFieldRepository; + this.paymentManager = paymentManager; + this.notificationManager = notificationManager; + this.messageSourceManager = messageSourceManager; + this.templateManager = templateManager; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.auditingRepository = auditingRepository; + this.userRepository = userRepository; + this.extensionManager = extensionManager; + this.billingDocumentRepository = billingDocumentRepository; + this.fileUploadManager = fileUploadManager; + this.promoCodeDiscountRepository = promoCodeDiscountRepository; + this.additionalServiceRepository = additionalServiceRepository; + this.billingDocumentManager = billingDocumentManager; + this.clockProvider = clockProvider; + this.subscriptionRepository = subscriptionRepository; + this.reservationEmailContentHelper = reservationEmailContentHelper; + } //the following methods have an explicit transaction handling, therefore the @Transactional annotation is not helpful here Result, PurchaseContext>> confirmReservation(PurchaseContextType purchaseContextType, @@ -127,25 +187,26 @@ Result, PurchaseContext>> confirmReservat UUID subscriptionId) { DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); TransactionTemplate template = new TransactionTemplate(transactionManager, definition); - return template.execute(status -> { + Result result = template.execute(status -> { try { - Result, PurchaseContext>> result = purchaseContextManager.findBy(purchaseContextType, eventName) + Result confirmationResult = purchaseContextManager.findBy(purchaseContextType, eventName) .map(purchaseContext -> ticketReservationRepository.findOptionalReservationById(reservationId) .filter(r -> r.getStatus() == TicketReservationStatus.PENDING || r.getStatus() == TicketReservationStatus.STUCK) .map(r -> performConfirmation(reservationId, purchaseContext, r, notification, username, subscriptionId)) .orElseGet(() -> Result.error(ErrorCode.ReservationError.UPDATE_FAILED)) ).orElseGet(() -> Result.error(ErrorCode.ReservationError.NOT_FOUND)); - if(!result.isSuccess()) { + if(!confirmationResult.isSuccess()) { log.debug("Reservation confirmation failed for eventName: {} reservationId: {}, username: {}", eventName, reservationId, username); status.setRollbackOnly(); } - return result; + return confirmationResult; } catch (Exception e) { log.error("Error during confirmation of reservation eventName: {} reservationId: {}, username: {}", eventName, reservationId, username); status.setRollbackOnly(); return Result.error(singletonList(ErrorCode.custom("", e.getMessage()))); } }); + return requireNonNull(result).flatMap(this::loadReservation); } public Result, PurchaseContext>> confirmReservation(PurchaseContextType purchaseContextType, String eventName, @@ -189,12 +250,13 @@ public Result>> createReservation(AdminRese .map(r -> r.flatMap(p -> transactionalCreateReservation(p.getRight(), p.getLeft(), username))) .orElse(Result.error(ErrorCode.EventError.NOT_FOUND)); if (!result.isSuccess()) { - log.debug("Error during update of reservation eventName: {}, username: {}, reservation: {}", eventName, username, AdminReservationModification.summary(input)); + log.warn("Error during update of reservation eventName: {}, username: {}, reservation: {}", eventName, username, AdminReservationModification.summary(input)); status.rollbackToSavepoint(savepoint); } return result; } catch (Exception e) { log.error("Error during update of reservation eventName: {}, username: {}, reservation: {}", eventName, username, AdminReservationModification.summary(input)); + log.debug("Error detail:", e); status.rollbackToSavepoint(savepoint); return Result.error(singletonList(ErrorCode.custom(e instanceof DuplicateReferenceException ? "duplicate-reference" : "", e.getMessage()))); } @@ -244,7 +306,7 @@ private void sendTicketToAttendees(Event event, TicketReservation reservation, P .forEach(t -> { Locale locale = LocaleUtil.forLanguageTag(t.getUserLanguage()); var additionalInfo = ticketReservationManager.retrieveAttendeeAdditionalInfoForTicket(t); - ticketReservationManager.sendTicketByEmail(t, locale, event, ticketReservationManager.getTicketEmailGenerator(event, reservation, locale, additionalInfo)); + reservationEmailContentHelper.sendTicketByEmail(t, locale, event, ticketReservationManager.getTicketEmailGenerator(event, reservation, locale, additionalInfo)); }); } @@ -281,8 +343,8 @@ private Result performUpdate(String reservationId, PurchaseContext purc auditingRepository.insert(reservationId, userRepository.getByUsername(username).getId(), purchaseContext, Audit.EventType.FORCE_VAT_APPLICATION, new Date(), Audit.EntityType.RESERVATION, reservationId, singletonList(singletonMap("vatStatus", newVatStatus))); ticketReservationRepository.addReservationInvoiceOrReceiptModel(reservationId, null); var newPrice = ticketReservationManager.totalReservationCostWithVAT(r.withVatStatus(newVatStatus)).getLeft(); - ticketReservationRepository.resetVat(reservationId, r.isInvoiceRequested(), newVatStatus, r.getSrcPriceCts(), newPrice.getPriceWithVAT(), - newPrice.getVAT(), Math.abs(newPrice.getDiscount()), r.getCurrencyCode()); + ticketReservationRepository.resetVat(reservationId, r.isInvoiceRequested(), newVatStatus, r.getSrcPriceCts(), newPrice.priceWithVAT(), + newPrice.VAT(), Math.abs(newPrice.discount()), r.getCurrencyCode()); } } @@ -330,6 +392,22 @@ public Result, PurchaseContext>> loadRese .orElseGet(() -> Result.error(ErrorCode.ReservationError.NOT_FOUND)); } + @Transactional + public List getTicketIdsWithAdditionalData(PurchaseContextType purchaseContextType, String publicIdentifier, String reservationId) { + if(purchaseContextType != PurchaseContextType.event) { + return List.of(); + } + return ticketRepository.findTicketsWithAdditionalData(reservationId, publicIdentifier); + } + + @Transactional + public Optional> loadFullTicketInfo(String reservationId, String eventShortName, String ticketUUID) { + return purchaseContextManager.findBy(PurchaseContextType.event, eventShortName) + .flatMap(event -> ticketRepository.findOptionalByUUID(ticketUUID) + .filter(ticket -> reservationId.equals(ticket.getTicketsReservationId())) + .map(ticket -> Pair.of((Event) event, ticket))); + } + private Result, PurchaseContext>> loadReservation(String reservationId) { return ticketReservationRepository.findOptionalReservationById(reservationId) @@ -338,12 +416,12 @@ private Result, PurchaseContext>> loadRes .orElseGet(() -> Result.error(ErrorCode.ReservationError.NOT_FOUND)); } - private Result, PurchaseContext>> performConfirmation(String reservationId, - PurchaseContext purchaseContext, - TicketReservation original, - Notification notification, - String username, - UUID subscriptionId) { + private Result performConfirmation(String reservationId, + PurchaseContext purchaseContext, + TicketReservation original, + Notification notification, + String username, + UUID subscriptionId) { try { var reservation = original; @@ -367,6 +445,8 @@ private Result, PurchaseContext>> perform .findFirst() .map(DefaultMessageSourceResolvable::getCode) .orElse("Unknown error"); + log.warn("Unable to apply subscription {}: {}", subscriptionId, + bindingResult.getAllErrors().stream().map(ObjectError::getCode).collect(joining(", "))); return Result.error(ErrorCode.custom(message, String.format("Cannot assign subscription %s to Reservation %s", subscriptionId, reservationId))); } @@ -396,7 +476,7 @@ private Result, PurchaseContext>> perform notification.isCustomer(), notification.isAttendees(), username); - return loadReservation(reservationId); + return Result.success(reservationId); } catch(Exception e) { return Result.error(ErrorCode.ReservationError.UPDATE_FAILED); } @@ -578,8 +658,8 @@ private void updateExtRefAndLocking(int categoryId, Attendee attendee, Integer t try { ticketRepository.updateExternalReferenceAndLocking(ticketId, categoryId, StringUtils.trimToNull(attendee.getReference()), attendee.isReassignmentForbidden()); } catch (DataIntegrityViolationException ex) { - log.warn("Duplicate found for external reference: "+attendee.getReference()+" and ticketID: " + ticketId); - throw new DuplicateReferenceException("Duplicated Reference: "+attendee.getReference(), ex); + log.warn("Duplicate found for external reference: {} and ticketID: {}", attendee.getReference(), ticketId); + throw new DuplicateReferenceException("Duplicated Reference: " + attendee.getReference(), ex); } } @@ -653,8 +733,8 @@ private void createMissingTickets(Event event, int tickets) { } @Transactional - public void removeTickets(String publicIdentifier, String reservationId, List ticketIds, List toRefund, boolean notify, boolean issueCreditNote, String username) { - loadReservation(PurchaseContextType.event, publicIdentifier, reservationId, username).ifSuccess(res -> { + public Result removeTickets(String publicIdentifier, String reservationId, List ticketIds, List toRefund, boolean notify, boolean creditNoteRequested, String username) { + return loadReservation(PurchaseContextType.event, publicIdentifier, reservationId, username).map(res -> { Event e = res.getRight().event().orElseThrow(); TicketReservation reservation = res.getLeft(); List tickets = res.getMiddle(); @@ -663,11 +743,18 @@ public void removeTickets(String publicIdentifier, String reservationId, List ticketIds.contains(t.getId())))) { + throw new IncompatibleStateException("Cannot remove checked-in tickets"); + } // handleTicketsRefund(toRefund, e, reservation, ticketsById, username); boolean removeReservation = tickets.size() - ticketIds.size() <= 0; + boolean issueCreditNote = (creditNoteRequested && + // if payment method supports refund we require that the user has selected at least one ticket + (!toRefund.isEmpty() || !reservation.getPaymentMethod().isSupportRefund()) + ); removeTicketsFromReservation(reservation, e, ticketIds, notify, username, removeReservation, issueCreditNote); // @@ -677,7 +764,7 @@ public void removeTickets(String publicIdentifier, String reservationId, List additionalServiceItems = additionalServiceItemRepository.findByReservationUuid(reservationId); @@ -687,6 +774,7 @@ public void removeTickets(String publicIdentifier, String reservationId, List removeReservation(PurchaseContextType purchaseContextType @Transactional public void creditReservation(PurchaseContextType purchaseContextType, String publicIdentifier, String reservationId, boolean refund, boolean notify, String username) { - loadReservation(purchaseContextType, publicIdentifier, reservationId, username).flatMap(res -> removeReservation(res, refund, notify, username, false, true)); + loadReservation(purchaseContextType, publicIdentifier, reservationId, username) + .ifSuccess(res -> { + if (res.getLeft().getStatus() == TicketReservationStatus.OFFLINE_PAYMENT) { + ticketReservationManager.deleteOfflinePayment(res.getRight().event().orElseThrow(), reservationId, false, true, notify, username); + } else { + removeReservation(res, refund, notify, username, false, true); + } + }); } private Result> removeReservation(Triple, PurchaseContext> triple, @@ -816,7 +911,11 @@ private ErrorCode refundIfRequested(TicketReservation reservation, PurchaseConte } private boolean ticketsStatusIsCompatibleWithCancellation(List tickets) { - return tickets.stream().noneMatch(c -> c.getStatus() == Ticket.TicketStatus.CHECKED_IN); + return ticketsStatusIsCompatibleWithCancellation(tickets.stream()); + } + + private boolean ticketsStatusIsCompatibleWithCancellation(Stream ticketsStream) { + return ticketsStream.noneMatch(c -> c.getStatus() == Ticket.TicketStatus.CHECKED_IN); } @Transactional diff --git a/src/main/java/alfio/manager/AdminReservationRequestManager.java b/src/main/java/alfio/manager/AdminReservationRequestManager.java index 865c502ac0..fc04ac6812 100644 --- a/src/main/java/alfio/manager/AdminReservationRequestManager.java +++ b/src/main/java/alfio/manager/AdminReservationRequestManager.java @@ -25,12 +25,12 @@ import alfio.repository.AdminReservationRequestRepository; import alfio.repository.EventRepository; import alfio.repository.user.UserRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.stereotype.Component; @@ -52,10 +52,10 @@ @Component @Transactional -@Log4j2 -@RequiredArgsConstructor public class AdminReservationRequestManager { + private static final Logger log = LoggerFactory.getLogger(AdminReservationRequestManager.class); + private final AdminReservationManager adminReservationManager; private final EventManager eventManager; private final UserRepository userRepository; @@ -63,6 +63,20 @@ public class AdminReservationRequestManager { private final EventRepository eventRepository; private final PlatformTransactionManager transactionManager; + public AdminReservationRequestManager(AdminReservationManager adminReservationManager, + EventManager eventManager, + UserRepository userRepository, + AdminReservationRequestRepository adminReservationRequestRepository, + EventRepository eventRepository, + PlatformTransactionManager transactionManager) { + this.adminReservationManager = adminReservationManager; + this.eventManager = eventManager; + this.userRepository = userRepository; + this.adminReservationRequestRepository = adminReservationRequestRepository; + this.eventRepository = eventRepository; + this.transactionManager = transactionManager; + } + public Result getRequestStatus(String requestId, String eventName, String username) { return eventManager.getOptionalEventAndOrganizationIdByName(eventName, username) .flatMap(e -> adminReservationRequestRepository.findStatsByRequestIdAndEventId(requestId, e.getId())) @@ -89,8 +103,7 @@ public Result scheduleReservations(String eventName, .entrySet().stream() .filter(e -> e.getValue() > 1) .map(Map.Entry::getKey) - .limit(5) // return max 5 codes - .collect(Collectors.toList()); + .limit(5).toList(); if(!attendeesWithDuplicateReference.isEmpty()) { return Result.error(ErrorCode.custom("DUPLICATE_REFERENCE", "The following codes are duplicate:" + attendeesWithDuplicateReference)); @@ -120,7 +133,7 @@ public Pair processPendingReservations() { try { adminReservationRequestRepository.updateStatus(list); } catch(Exception e) { - log.fatal("cannot update the status of "+list.size()+" reservations", e); + log.warn("cannot update the status of "+list.size()+" reservations", e); } }); @@ -147,6 +160,7 @@ private Result, Event>> processReservatio .map(triple -> Triple.of(triple.getLeft(), triple.getMiddle(), (Event) triple.getRight())); if(!result.isSuccess()) { status.rollbackToSavepoint(savepoint); + log.warn("Cannot process reservation: \n{}", result.getFormattedErrors()); } return result; } catch(Exception ex) { @@ -158,6 +172,9 @@ private Result, Event>> processReservatio private MapSqlParameterSource buildParameterSource(Long id, Result, Event>> result) { boolean success = result.isSuccess(); + if (!success) { + log.warn("Cannot process request {}. Got the following errors:\n{}", id, result.getFormattedErrors()); + } return new MapSqlParameterSource("id", id) .addValue("status", success ? AdminReservationRequest.Status.SUCCESS.name() : AdminReservationRequest.Status.ERROR.name()) .addValue("reservationId", success ? result.getData().getLeft().getId() : null) diff --git a/src/main/java/alfio/manager/AttendeeManager.java b/src/main/java/alfio/manager/AttendeeManager.java index 6cdd14f71a..61fb06554c 100644 --- a/src/main/java/alfio/manager/AttendeeManager.java +++ b/src/main/java/alfio/manager/AttendeeManager.java @@ -29,19 +29,18 @@ import alfio.repository.user.UserRepository; import alfio.util.ClockProvider; import alfio.util.EventUtil; -import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; +import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; @Component -@AllArgsConstructor public class AttendeeManager { + public static final String DEFAULT_OPERATOR_ID = "__DEFAULT__"; private final SponsorScanRepository sponsorScanRepository; private final EventRepository eventRepository; private final TicketRepository ticketRepository; @@ -51,7 +50,30 @@ public class AttendeeManager { private final AdditionalServiceItemRepository additionalServiceItemRepository; private final ClockProvider clockProvider; - public TicketAndCheckInResult registerSponsorScan(String eventShortName, String ticketUid, String notes, SponsorScan.LeadStatus leadStatus, String username) { + public AttendeeManager(SponsorScanRepository sponsorScanRepository, + EventRepository eventRepository, + TicketRepository ticketRepository, + UserRepository userRepository, + UserManager userManager, + TicketFieldRepository ticketFieldRepository, + AdditionalServiceItemRepository additionalServiceItemRepository, + ClockProvider clockProvider) { + this.sponsorScanRepository = sponsorScanRepository; + this.eventRepository = eventRepository; + this.ticketRepository = ticketRepository; + this.userRepository = userRepository; + this.userManager = userManager; + this.ticketFieldRepository = ticketFieldRepository; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.clockProvider = clockProvider; + } + + public TicketAndCheckInResult registerSponsorScan(String eventShortName, + String ticketUid, + String notes, + SponsorScan.LeadStatus leadStatus, + String username, + String operatorId) { int userId = userRepository.getByUsername(username).getId(); Optional maybeEvent = eventRepository.findOptionalEventAndOrganizationIdByShortName(eventShortName); if(maybeEvent.isEmpty()) { @@ -66,12 +88,13 @@ public TicketAndCheckInResult registerSponsorScan(String eventShortName, String if(ticket.getStatus() != Ticket.TicketStatus.CHECKED_IN) { return new TicketAndCheckInResult(new TicketWithCategory(ticket, null), new DefaultCheckInResult(CheckInStatus.INVALID_TICKET_STATE, "not checked-in")); } - Optional existingRegistration = sponsorScanRepository.getRegistrationTimestamp(userId, event.getId(), ticket.getId()); + var operator = Objects.requireNonNullElse(operatorId, DEFAULT_OPERATOR_ID); + Optional existingRegistration = sponsorScanRepository.getRegistrationTimestamp(userId, event.getId(), ticket.getId(), operator); if(existingRegistration.isEmpty()) { ZoneId eventZoneId = eventRepository.getZoneIdByEventId(event.getId()); - sponsorScanRepository.insert(userId, ZonedDateTime.now(clockProvider.withZone(eventZoneId)), event.getId(), ticket.getId(), notes, leadStatus); + sponsorScanRepository.insert(userId, ZonedDateTime.now(clockProvider.withZone(eventZoneId)), event.getId(), ticket.getId(), notes, leadStatus, operator); } else { - sponsorScanRepository.updateNotesAndLeadStatus(userId, event.getId(), ticket.getId(), notes, leadStatus); + sponsorScanRepository.updateNotesAndLeadStatus(userId, event.getId(), ticket.getId(), notes, leadStatus, operator); } return new TicketAndCheckInResult(new TicketWithCategory(ticket, null), new DefaultCheckInResult(CheckInStatus.SUCCESS, "success")); } @@ -107,7 +130,9 @@ private List loadAttendeesData(EventAndOrganizationId event .map(scan -> { Ticket ticket = scan.getTicket(); return new SponsorAttendeeData(ticket.getUuid(), scan.getSponsorScan().getTimestamp().format(EventUtil.JSON_DATETIME_FORMATTER), ticket.getFullName(), ticket.getEmail()); - }).collect(Collectors.toList()); + }) + .distinct() + .toList(); } } diff --git a/src/main/java/alfio/manager/BillingDocumentManager.java b/src/main/java/alfio/manager/BillingDocumentManager.java index b3ed54a0e4..45b9b705ca 100644 --- a/src/main/java/alfio/manager/BillingDocumentManager.java +++ b/src/main/java/alfio/manager/BillingDocumentManager.java @@ -30,10 +30,10 @@ import alfio.util.Json; import alfio.util.TemplateResource; import ch.digitalfondue.npjt.AffectedRowCountAndKey; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -48,18 +48,20 @@ import static alfio.model.TicketReservation.TicketReservationStatus.CANCELLED; import static alfio.model.TicketReservation.TicketReservationStatus.PENDING; import static alfio.model.system.ConfigurationKeys.*; +import static alfio.util.ReservationUtil.collectTicketsWithCategory; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; import static org.apache.commons.lang3.StringUtils.trimToNull; +import static org.springframework.http.MediaType.APPLICATION_PDF_VALUE; @Component -@AllArgsConstructor -@Log4j2 public class BillingDocumentManager { + + private static final Logger log = LoggerFactory.getLogger(BillingDocumentManager.class); + static final String CREDIT_NOTE_NUMBER = "creditNoteNumber"; - private static final String APPLICATION_PDF = "application/pdf"; private final BillingDocumentRepository billingDocumentRepository; private final Json json; private final ConfigurationManager configurationManager; @@ -73,6 +75,32 @@ public class BillingDocumentManager { private final ExtensionManager extensionManager; private final InvoiceSequencesRepository invoiceSequencesRepository; + public BillingDocumentManager(BillingDocumentRepository billingDocumentRepository, + Json json, + ConfigurationManager configurationManager, + TicketRepository ticketRepository, + TicketCategoryRepository ticketCategoryRepository, + OrganizationRepository organizationRepository, + UserRepository userRepository, + AuditingRepository auditingRepository, + TicketReservationRepository ticketReservationRepository, + ClockProvider clockProvider, + ExtensionManager extensionManager, + InvoiceSequencesRepository invoiceSequencesRepository) { + this.billingDocumentRepository = billingDocumentRepository; + this.json = json; + this.configurationManager = configurationManager; + this.ticketRepository = ticketRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.organizationRepository = organizationRepository; + this.userRepository = userRepository; + this.auditingRepository = auditingRepository; + this.ticketReservationRepository = ticketReservationRepository; + this.clockProvider = clockProvider; + this.extensionManager = extensionManager; + this.invoiceSequencesRepository = invoiceSequencesRepository; + } + public Optional findFirstInvoiceDate(int eventId) { return billingDocumentRepository.findFirstInvoiceGenerationDate(eventId); @@ -86,7 +114,7 @@ static boolean mustGenerateBillingDocument(OrderSummary summary, TicketReservati return !summary.getFree() && (!summary.getNotYetPaid() || (summary.getWaitingForPayment() && ticketReservation.isInvoiceRequested())); } - List generateBillingDocumentAttachment(PurchaseContext purchaseContext, + public List generateBillingDocumentAttachment(PurchaseContext purchaseContext, TicketReservation ticketReservation, Locale language, BillingDocument.Type documentType, @@ -96,17 +124,15 @@ List generateBillingDocumentAttachment(PurchaseContext purcha model.put("reservationId", ticketReservation.getId()); model.put("eventId", purchaseContext.event().map(ev -> Integer.toString(ev.getId())).orElse(null)); model.put("language", json.asJsonString(language)); - model.put("reservationEmailModel", json.asJsonString(getOrCreateBillingDocument(purchaseContext, ticketReservation, username, orderSummary).getModel())); - switch (documentType) { - case INVOICE: - return Collections.singletonList(new Mailer.Attachment("invoice.pdf", null, APPLICATION_PDF, model, Mailer.AttachmentIdentifier.INVOICE_PDF)); - case RECEIPT: - return Collections.singletonList(new Mailer.Attachment("receipt.pdf", null, APPLICATION_PDF, model, Mailer.AttachmentIdentifier.RECEIPT_PDF)); - case CREDIT_NOTE: - return Collections.singletonList(new Mailer.Attachment("credit-note.pdf", null, APPLICATION_PDF, model, Mailer.AttachmentIdentifier.CREDIT_NOTE_PDF)); - default: - throw new IllegalStateException(documentType+" is not supported"); - } + model.put("reservationEmailModel", json.asJsonString(internalGetOrCreate(purchaseContext, ticketReservation, username, orderSummary).getModel())); + return switch (documentType) { + case INVOICE -> + Collections.singletonList(new Mailer.Attachment("invoice.pdf", null, APPLICATION_PDF_VALUE, model, Mailer.AttachmentIdentifier.INVOICE_PDF)); + case RECEIPT -> + Collections.singletonList(new Mailer.Attachment("receipt.pdf", null, APPLICATION_PDF_VALUE, model, Mailer.AttachmentIdentifier.RECEIPT_PDF)); + case CREDIT_NOTE -> + Collections.singletonList(new Mailer.Attachment("credit-note.pdf", null, APPLICATION_PDF_VALUE, model, Mailer.AttachmentIdentifier.CREDIT_NOTE_PDF)); + }; } @Transactional @@ -144,6 +170,10 @@ BillingDocument createBillingDocument(PurchaseContext purchaseContext, TicketRes @Transactional public BillingDocument getOrCreateBillingDocument(PurchaseContext purchaseContext, TicketReservation reservation, String username, OrderSummary orderSummary) { + return internalGetOrCreate(purchaseContext, reservation, username, orderSummary); + } + + private BillingDocument internalGetOrCreate(PurchaseContext purchaseContext, TicketReservation reservation, String username, OrderSummary orderSummary) { Optional existing = billingDocumentRepository.findLatestByReservationId(reservation.getId()); return existing.orElseGet(() -> createBillingDocument(purchaseContext, reservation, username, orderSummary)); } @@ -220,15 +250,7 @@ private Map prepareModelForBillingDocument(PurchaseContext purch Map> ticketsByCategory = ticketRepository.findTicketsInReservation(reservation.getId()) .stream() .collect(groupingBy(Ticket::getCategoryId)); - final List ticketsWithCategory; - if(!ticketsByCategory.isEmpty()) { - ticketsWithCategory = ticketCategoryRepository.findByIds(ticketsByCategory.keySet()) - .stream() - .flatMap(tc -> ticketsByCategory.get(tc.getId()).stream().map(t -> new TicketWithCategory(t, tc))) - .collect(toList()); - } else { - ticketsWithCategory = Collections.emptyList(); - } + List ticketsWithCategory = collectTicketsWithCategory(ticketsByCategory, ticketCategoryRepository); var reservationShortId = configurationManager.getShortReservationID(purchaseContext, reservation); Map model = TemplateResource.prepareModelForConfirmationEmail(organization, purchaseContext, reservation, vat, ticketsWithCategory, summary, "", "", reservationShortId, invoiceAddress, bankAccountNr, bankAccountOwner, Map.of()); boolean euBusiness = StringUtils.isNotBlank(reservation.getVatCountryCode()) && StringUtils.isNotBlank(reservation.getVatNr()) @@ -239,6 +261,7 @@ private Map prepareModelForBillingDocument(PurchaseContext purch model.put("publicId", configurationManager.getPublicReservationID(purchaseContext, reservation)); var additionalInfo = ticketReservationRepository.getAdditionalInfo(reservation.getId()); model.put("invoicingAdditionalInfo", additionalInfo.getInvoicingAdditionalInfo()); + model.put("proforma", !additionalInfo.getInvoicingAdditionalInfo().isEmpty()); model.put("billingDetails", additionalInfo.getBillingDetails()); if(type == CREDIT_NOTE) { model.put(CREDIT_NOTE_NUMBER, creditNoteNumber); diff --git a/src/main/java/alfio/manager/CheckInManager.java b/src/main/java/alfio/manager/CheckInManager.java index 7e75579f48..cb1f1f1c23 100644 --- a/src/main/java/alfio/manager/CheckInManager.java +++ b/src/main/java/alfio/manager/CheckInManager.java @@ -20,7 +20,10 @@ import alfio.manager.system.ConfigurationManager; import alfio.model.*; import alfio.model.Ticket.TicketStatus; +import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.audit.ScanAudit; +import alfio.model.checkin.AttendeeSearchResults; +import alfio.model.decorator.TicketPriceContainer; import alfio.model.support.CheckInOutputColorConfiguration; import alfio.model.transaction.PaymentProxy; import alfio.repository.*; @@ -29,21 +32,20 @@ import alfio.repository.user.UserRepository; import alfio.util.*; import com.google.gson.reflect.TypeToken; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; @@ -66,11 +68,12 @@ @Component @Transactional -@Log4j2 -@AllArgsConstructor public class CheckInManager { + private static final Logger log = LoggerFactory.getLogger(CheckInManager.class); + static final Pattern CYPHER_SPLITTER = Pattern.compile("\\|"); + private static final int SEARCH_ATTENDEES_LIMIT = 20; private final TicketRepository ticketRepository; private final EventRepository eventRepository; private final TicketReservationRepository ticketReservationRepository; @@ -87,6 +90,38 @@ public class CheckInManager { private final PollRepository pollRepository; private final ClockProvider clockProvider; + public CheckInManager(TicketRepository ticketRepository, + EventRepository eventRepository, + TicketReservationRepository ticketReservationRepository, + TicketFieldRepository ticketFieldRepository, + TicketCategoryRepository ticketCategoryRepository, + ScanAuditRepository scanAuditRepository, + AuditingRepository auditingRepository, + ConfigurationManager configurationManager, + OrganizationRepository organizationRepository, + UserRepository userRepository, + TicketReservationManager ticketReservationManager, + ExtensionManager extensionManager, + AdditionalServiceItemRepository additionalServiceItemRepository, + PollRepository pollRepository, + ClockProvider clockProvider) { + this.ticketRepository = ticketRepository; + this.eventRepository = eventRepository; + this.ticketReservationRepository = ticketReservationRepository; + this.ticketFieldRepository = ticketFieldRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.scanAuditRepository = scanAuditRepository; + this.auditingRepository = auditingRepository; + this.configurationManager = configurationManager; + this.organizationRepository = organizationRepository; + this.userRepository = userRepository; + this.ticketReservationManager = ticketReservationManager; + this.extensionManager = extensionManager; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.pollRepository = pollRepository; + this.clockProvider = clockProvider; + } + private void checkIn(String uuid) { Ticket ticket = ticketRepository.findByUUID(uuid); @@ -100,7 +135,31 @@ private void acquire(String uuid) { Ticket ticket = ticketRepository.findByUUID(uuid); Validate.isTrue(ticket.getStatus() == TicketStatus.TO_BE_PAID); ticketRepository.updateTicketStatusWithUUID(uuid, TicketStatus.ACQUIRED.toString()); - ticketReservationManager.registerAlfioTransaction(eventRepository.findById(ticket.getEventId()), ticket.getTicketsReservationId(), PaymentProxy.ON_SITE); + ticketReservationManager.registerAlfioTransactionForOnsitePayment(eventRepository.findById(ticket.getEventId()), ticket.getTicketsReservationId()); + } + + public AttendeeSearchResults searchAttendees(Event event, String query, int page) { + if (StringUtils.isBlank(query)) { + return new AttendeeSearchResults(0, 0, 0, 0, List.of()); + } + int eventId = event.getId(); + var search = "%" + query + "%"; + var results = ticketRepository.searchAttendees(eventId, search, SEARCH_ATTENDEES_LIMIT, SEARCH_ATTENDEES_LIMIT * page); + var statistics = ticketRepository.countSearchResults(eventId, search); + var attendees = results.stream().map(fi -> { + var ticket = fi.getTicket(); + var reservation = fi.getTicketReservation(); + String amountToPay = null; + if (reservation.getPaymentMethod() == PaymentProxy.ON_SITE) { + var priceContainer = TicketPriceContainer.from(ticket, reservation.getVatStatus(), reservation.getVAT(), event.getVatStatus(), reservation.getDiscount().orElse(null)); + amountToPay = event.getCurrency() + " " + MonetaryUtil.formatUnit(priceContainer.getFinalPrice(), event.getCurrency()); + } + return new AttendeeSearchResults.Attendee(ticket.getUuid(), ticket.getFirstName(), + ticket.getLastName(), fi.getTicketCategory().getName(), fi.getTicketAdditionalInfo(), + ticket.getStatus(), amountToPay); + }).collect(Collectors.toList()); + int totalPages = (int) Math.ceil((statistics.getTotal() / (double) SEARCH_ATTENDEES_LIMIT)); + return new AttendeeSearchResults(statistics.getTotal(), statistics.getCheckedIn(), totalPages, page, attendees); } /** @@ -276,7 +335,7 @@ private TicketAndCheckInResult extractStatus(Optional isOfflineCheckInAndLabelPrintingEnabled public Map getEncryptedAttendeesInformation(Event ev, Set additionalFields, List ids) { - return Optional.ofNullable(ev).filter(isOfflineCheckInEnabled()).map(event -> { + boolean caseInsensitiveQRCode = ev.supportsQRCodeCaseInsensitive(); Map categories = ticketCategoryRepository.findByEventIdAsMap(event.getId()); String eventKey = event.getPrivateKey(); - Function hashedHMAC = ticket -> DigestUtils.sha256Hex(ticket.hmacTicketInfo(eventKey)); + Function hashedHMAC = ticket -> DigestUtils.sha256Hex(ticket.hmacTicketInfo(eventKey, caseInsensitiveQRCode)); var outputColorConfiguration = getOutputColorConfiguration(event, configurationManager); // fetch polls for event, in order to determine if we have to print PIN or not var polls = pollRepository.findAllForEvent(event.getId()); boolean hasPolls = !polls.isEmpty(); - var allowedTags = hasPolls ? polls.stream().flatMap(p -> p.getAllowedTags().stream()).collect(Collectors.toList()) : List.of(); + var allowedTags = hasPolls ? polls.stream().flatMap(p -> p.allowedTags().stream()).collect(Collectors.toList()) : List.of(); Function encryptedBody = ticket -> { Map info = new HashMap<>(); @@ -401,6 +460,7 @@ public Map getEncryptedAttendeesInformation(Event ev, Set if (!additionalFields.isEmpty()) { Map fields = new HashMap<>(); fields.put("company", trimToEmpty(ticket.getBillingDetails().getCompanyName())); + fields.put("category", ticket.getTicketCategory().getName()); fields.putAll(ticketFieldRepository.findValueForTicketId(ticket.getId(), additionalFields).stream() .map(vd -> { try { @@ -443,7 +503,7 @@ public Map getEncryptedAttendeesInformation(Event ev, Set if(!additionalServicesInfo.isEmpty()) { info.put("additionalServicesInfoJson", Json.toJson(additionalServicesInfo)); } - String key = ticket.ticketCode(eventKey); + String key = ticket.ticketCode(eventKey, caseInsensitiveQRCode); return encrypt(key, Json.toJson(info)); }; return ticketRepository.findAllFullTicketInfoAssignedByEventId(event.getId(), ids) @@ -487,12 +547,12 @@ List getAdditionalServicesForTicket(TicketInfoContainer t List additionalServices = additionalServiceItemRepository.getAdditionalServicesBookedForReservation(ticketsReservationId, ticket.getUserLanguage(), ticket.getEventId()); boolean additionalServicesEmpty = additionalServices.isEmpty(); if(!additionalServicesEmpty) { - List additionalServiceIds = additionalServices.stream().map(BookedAdditionalService::getAdditionalServiceId).collect(Collectors.toList()); + List additionalServiceIds = additionalServices.stream().map(BookedAdditionalService::additionalServiceId).collect(Collectors.toList()); Map> fields = ticketFieldRepository.loadTicketFieldsForAdditionalService(ticket.getId(), additionalServiceIds) .stream().collect(Collectors.groupingBy(TicketFieldValueForAdditionalService::getAdditionalServiceId)); return additionalServices.stream() - .map(as -> new AdditionalServiceInfo(as.getAdditionalServiceName(), as.getCount(), fields.get(as.getAdditionalServiceId()))) + .map(as -> new AdditionalServiceInfo(as.additionalServiceName(), as.count(), fields.get(as.additionalServiceId()))) .collect(Collectors.toList()); } return List.of(); @@ -506,6 +566,13 @@ public CheckInStatistics getStatistics(String eventName, String username) { .orElse(null); } + public List retrieveLogEntries(String eventName, String username) { + return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) + .filter(EventManager.checkOwnership(username, organizationRepository)) + .map(event -> scanAuditRepository.loadEntries(event.getId())) + .orElse(List.of()); + } + private boolean areStatsEnabled(EventAndOrganizationId event) { return configurationManager.getFor(CHECK_IN_STATS, event.getConfigurationLevel()).getValueAsBooleanOrDefault(); } diff --git a/src/main/java/alfio/manager/DemoModeDataManager.java b/src/main/java/alfio/manager/DemoModeDataManager.java index 65c1c769ed..d11ab52971 100644 --- a/src/main/java/alfio/manager/DemoModeDataManager.java +++ b/src/main/java/alfio/manager/DemoModeDataManager.java @@ -22,31 +22,49 @@ import alfio.model.user.User; import alfio.repository.EventDeleterRepository; import alfio.repository.EventRepository; +import alfio.repository.OrganizationDeleterRepository; import alfio.repository.user.OrganizationRepository; import alfio.repository.user.UserRepository; import alfio.repository.user.join.UserOrganizationRepository; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.time.DateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.transaction.annotation.Transactional; import java.util.Date; +import java.util.EnumSet; import java.util.List; +import java.util.Set; -@AllArgsConstructor -@Log4j2 public class DemoModeDataManager { + + private static final Logger log = LoggerFactory.getLogger(DemoModeDataManager.class); + private final UserRepository userRepository; private final UserOrganizationRepository userOrganizationRepository; - private final OrganizationRepository organizationRepository; private final EventDeleterRepository eventDeleterRepository; private final EventRepository eventRepository; private final ConfigurationManager configurationManager; + private final OrganizationDeleterRepository organizationDeleterRepository; + + public DemoModeDataManager(UserRepository userRepository, + UserOrganizationRepository userOrganizationRepository, + EventDeleterRepository eventDeleterRepository, + EventRepository eventRepository, + ConfigurationManager configurationManager, + OrganizationDeleterRepository organizationDeleterRepository) { + this.userRepository = userRepository; + this.userOrganizationRepository = userOrganizationRepository; + this.eventDeleterRepository = eventDeleterRepository; + this.eventRepository = eventRepository; + this.configurationManager = configurationManager; + this.organizationDeleterRepository = organizationDeleterRepository; + } public List findExpiredUsers(Date date) { - return userRepository.findUsersToDeleteOlderThan(date, User.Type.DEMO); + return userRepository.findUsersToDeleteOlderThan(date, Set.of(User.Type.DEMO.name(), User.Type.API_KEY.name())); } public void deleteAccounts(List userIds) { @@ -57,8 +75,7 @@ public void deleteAccounts(List userIds) { log.info("found {} events to delete", disabledEventIds.size()); disabledEventIds.forEach(eventDeleterRepository::deleteAllForEvent); userIds.forEach(userRepository::deleteUserAndReferences); - int deletedOrganizations = organizationRepository.deleteOrganizationsIfEmpty(organizationIds); - log.info("deleted {} empty organizations", deletedOrganizations); + organizationDeleterRepository.deleteEmptyOrganizations(organizationIds); } } diff --git a/src/main/java/alfio/manager/EuVatChecker.java b/src/main/java/alfio/manager/EuVatChecker.java index ec46b1ce8d..531d12163b 100644 --- a/src/main/java/alfio/manager/EuVatChecker.java +++ b/src/main/java/alfio/manager/EuVatChecker.java @@ -17,7 +17,10 @@ package alfio.manager; import alfio.manager.system.ConfigurationManager; -import alfio.model.*; +import alfio.model.Audit; +import alfio.model.Configurable; +import alfio.model.PurchaseContext; +import alfio.model.VatDetail; import alfio.model.system.ConfigurationKeys; import alfio.repository.AuditingRepository; import alfio.util.ItalianTaxIdValidator; @@ -25,8 +28,6 @@ import ch.digitalfondue.vatchecker.EUVatChecker; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; @@ -36,15 +37,12 @@ import java.util.*; import java.util.function.BiFunction; import java.util.function.BooleanSupplier; -import java.util.function.Supplier; import static alfio.model.Audit.EntityType.RESERVATION; import static alfio.model.Audit.EventType.*; import static alfio.model.system.ConfigurationKeys.*; @Component -@Log4j2 -@AllArgsConstructor public class EuVatChecker { private final ConfigurationManager configurationManager; @@ -56,6 +54,12 @@ public class EuVatChecker { .expireAfterWrite(Duration.ofMinutes(15)) .build(); + public EuVatChecker(ConfigurationManager configurationManager, AuditingRepository auditingRepository, ExtensionManager extensionManager) { + this.configurationManager = configurationManager; + this.auditingRepository = auditingRepository; + this.extensionManager = extensionManager; + } + public boolean isReverseChargeEnabledFor(PurchaseContext configurable) { return reverseChargeEnabled(configurationManager, configurable); } @@ -111,19 +115,11 @@ public void logSuccessfulValidation(VatDetail detail, String reservationId, Purc List> modifications = List.of( Map.of("vatNumber", detail.getVatNr(), "country", detail.getCountry(), "validationType", detail.getType()) ); - Audit.EventType eventType = null; - switch(detail.getType()) { - case VIES: - case EXTRA_EU: - eventType = VAT_VALIDATION_SUCCESSFUL; - break; - case SKIPPED: - eventType = VAT_VALIDATION_SKIPPED; - break; - case FORMAL: - eventType = VAT_FORMAL_VALIDATION_SUCCESSFUL; - break; - } + Audit.EventType eventType = switch (detail.getType()) { + case VIES, EXTRA_EU -> VAT_VALIDATION_SUCCESSFUL; + case SKIPPED -> VAT_VALIDATION_SKIPPED; + case FORMAL -> VAT_FORMAL_VALIDATION_SUCCESSFUL; + }; auditingRepository.insert(reservationId, null, purchaseContext, eventType, new Date(), RESERVATION, reservationId, modifications); } diff --git a/src/main/java/alfio/manager/EventManager.java b/src/main/java/alfio/manager/EventManager.java index 41a46dca2b..1239e11582 100644 --- a/src/main/java/alfio/manager/EventManager.java +++ b/src/main/java/alfio/manager/EventManager.java @@ -47,8 +47,6 @@ import alfio.util.MonetaryUtil; import alfio.util.RequestUtils; import ch.digitalfondue.npjt.AffectedRowCountAndKey; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.lang3.ObjectUtils; @@ -56,6 +54,8 @@ import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Triple; import org.flywaydb.core.Flyway; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; @@ -88,14 +88,14 @@ import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNullElse; import static java.util.Objects.requireNonNullElseGet; -import static java.util.stream.Collectors.*; +import static java.util.stream.Collectors.joining; @Component @Transactional -@Log4j2 -@AllArgsConstructor public class EventManager { + private static final Logger log = LoggerFactory.getLogger(EventManager.class); + private static final Predicate IS_CATEGORY_BOUNDED = TicketCategory::isBounded; static final String ERROR_ONLINE_ON_SITE_NOT_COMPATIBLE = "Cannot switch to Online. Please remove On-Site payment method first."; private final UserManager userManager; @@ -123,6 +123,56 @@ public class EventManager { private final ClockProvider clockProvider; private final SubscriptionRepository subscriptionRepository; + public EventManager(UserManager userManager, + EventRepository eventRepository, + EventDescriptionRepository eventDescriptionRepository, + TicketCategoryRepository ticketCategoryRepository, + TicketCategoryDescriptionRepository ticketCategoryDescriptionRepository, + TicketRepository ticketRepository, + SpecialPriceRepository specialPriceRepository, + PromoCodeDiscountRepository promoCodeRepository, + ConfigurationManager configurationManager, + TicketFieldRepository ticketFieldRepository, + EventDeleterRepository eventDeleterRepository, + AdditionalServiceRepository additionalServiceRepository, + AdditionalServiceTextRepository additionalServiceTextRepository, + Flyway flyway, + Environment environment, + OrganizationRepository organizationRepository, + AuditingRepository auditingRepository, + ExtensionManager extensionManager, + GroupRepository groupRepository, + NamedParameterJdbcTemplate jdbcTemplate, + ConfigurationRepository configurationRepository, + PaymentManager paymentManager, + ClockProvider clockProvider, + SubscriptionRepository subscriptionRepository) { + this.userManager = userManager; + this.eventRepository = eventRepository; + this.eventDescriptionRepository = eventDescriptionRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketCategoryDescriptionRepository = ticketCategoryDescriptionRepository; + this.ticketRepository = ticketRepository; + this.specialPriceRepository = specialPriceRepository; + this.promoCodeRepository = promoCodeRepository; + this.configurationManager = configurationManager; + this.ticketFieldRepository = ticketFieldRepository; + this.eventDeleterRepository = eventDeleterRepository; + this.additionalServiceRepository = additionalServiceRepository; + this.additionalServiceTextRepository = additionalServiceTextRepository; + this.flyway = flyway; + this.environment = environment; + this.organizationRepository = organizationRepository; + this.auditingRepository = auditingRepository; + this.extensionManager = extensionManager; + this.groupRepository = groupRepository; + this.jdbcTemplate = jdbcTemplate; + this.configurationRepository = configurationRepository; + this.paymentManager = paymentManager; + this.clockProvider = clockProvider; + this.subscriptionRepository = subscriptionRepository; + } + public Event getSingleEvent(String eventName, String username) { return getOptionalByName(eventName, username).orElseThrow(IllegalStateException::new); @@ -132,6 +182,10 @@ public EventAndOrganizationId getEventAndOrganizationId(String eventName, String return getOptionalEventAndOrganizationIdByName(eventName, username).orElseThrow(IllegalStateException::new); } + public List getEventIdsBySlug(List eventSlugs, int organizationId) { + return eventRepository.findIdsByShortNames(eventSlugs, organizationId); + } + public Optional getOptionalByName(String eventName, String username) { return eventRepository.findOptionalByShortName(eventName) .filter(checkOwnership(username, organizationRepository)); @@ -197,13 +251,15 @@ public void createEvent(EventModification em, String username) { .findFirst() .orElseThrow(); int eventId = insertEvent(em); + Optional srcEvent = getCopiedFrom(em, username); Event event = eventRepository.findById(eventId); createOrUpdateEventDescription(eventId, em); createAllAdditionalServices(eventId, em.getAdditionalServices(), event.getZoneId(), event.getCurrency()); createAdditionalFields(event, em); - createCategoriesForEvent(em, event); + createCategoriesForEvent(em, event, srcEvent); createAllTicketsForEvent(event, em); - createSubscriptionLinks(eventId, organization.getId(), em); + createSubscriptionLinks(eventId, organization.getId(), em.getLinkedSubscriptions()); + srcEvent.ifPresent(eventAndOrganizationId -> copySettings(event, eventAndOrganizationId)); extensionManager.handleEventCreation(event); var eventMetadata = extensionManager.handleMetadataUpdate(event, organization, AlfioMetadata.empty()); if(eventMetadata != null) { @@ -211,9 +267,28 @@ public void createEvent(EventModification em, String username) { } } - private void createSubscriptionLinks(int eventId, int organizationId, EventModification em) { - if(CollectionUtils.isNotEmpty(em.getLinkedSubscriptions())) { - var parameters = em.getLinkedSubscriptions().stream() + private Optional getCopiedFrom(EventModification em, String username) { + if (em.getMetadata() != null && StringUtils.isNotBlank(em.getMetadata().getCopiedFrom())) { + return getOptionalEventAndOrganizationIdByName(em.getMetadata().getCopiedFrom(), username); + } + return Optional.empty(); + } + + /** + * Copies settings from a copied event into the new one + * Supported settings are: + * - Event-specific configuration + * @param event event + * @param srcEvent source event + */ + private void copySettings(Event event, EventAndOrganizationId srcEvent) { + int count = configurationRepository.copyEventConfiguration(event.getId(), event.getOrganizationId(), srcEvent.getId(), srcEvent.getOrganizationId()); + log.info("copied {} settings from source event", count); + } + + private void createSubscriptionLinks(int eventId, int organizationId, List linkedSubscriptions) { + if(CollectionUtils.isNotEmpty(linkedSubscriptions)) { + var parameters = linkedSubscriptions.stream() .map(id -> new MapSqlParameterSource("eventId", eventId) .addValue("subscriptionId", id) .addValue("pricePerTicket", 0) @@ -410,11 +485,15 @@ public void updateEventPrices(EventAndOrganizationId original, EventModification } } int organizationId = original.getOrganizationId(); - if(CollectionUtils.isNotEmpty(em.getLinkedSubscriptions())) { - int removed = subscriptionRepository.removeStaleSubscriptions(eventId, organizationId, em.getLinkedSubscriptions()); + updateLinkedSubscriptions(em.getLinkedSubscriptions(), eventId, organizationId); + } + + public void updateLinkedSubscriptions(List linkedSubscriptions, int eventId, int organizationId) { + if(CollectionUtils.isNotEmpty(linkedSubscriptions)) { + int removed = subscriptionRepository.removeStaleSubscriptions(eventId, organizationId, linkedSubscriptions); log.trace("removed {} subscription links", removed); - createSubscriptionLinks(eventId, organizationId, em); - } else if (em.getLinkedSubscriptions() != null) { + createSubscriptionLinks(eventId, organizationId, linkedSubscriptions); + } else if (linkedSubscriptions != null) { // the user removed all the subscriptions int removed = subscriptionRepository.removeAllSubscriptionsForEvent(eventId, organizationId); log.trace("removed all subscription links ({}) for event {}", removed, eventId); @@ -631,7 +710,7 @@ private Stream generateTicketsForCategory(TicketCategory .map(ps -> buildTicketParams(event.getId(), creationDate, filteredTC, tc.getSrcPriceCts(), ps)); } - private void createCategoriesForEvent(EventModification em, Event event) { + private void createCategoriesForEvent(EventModification em, Event event, Optional srcEventOptional) { boolean freeOfCharge = em.isFreeOfCharge(); ZoneId zoneId = TimeZone.getTimeZone(event.getTimeZone()).toZoneId(); int eventId = event.getId(); @@ -665,6 +744,17 @@ private void createCategoriesForEvent(EventModification em, Event event) { final TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(category.getKey(), event.getId()); specialPriceRepository.bulkInsert(ticketCategory, ticketCategory.getMaxTickets()); } + + if (srcEventOptional.isPresent() && tc.getMetadata() != null && StringUtils.isNumeric(tc.getMetadata().getCopiedFrom())) { + int count = configurationRepository.copyCategoryConfiguration(event.getId(), + event.getOrganizationId(), + category.getKey(), + srcEventOptional.get().getId(), + srcEventOptional.get().getOrganizationId(), + Integer.parseInt(tc.getMetadata().getCopiedFrom()) + ); + log.info("Copied {} settings for category {}", count, tc.getName()); + } }); } @@ -707,19 +797,18 @@ void saveBadgeColorConfiguration(String badgeColor, Event event, Integer categor colorConfiguration = new CheckInOutputColorConfiguration("success", List.of(new ColorConfiguration(chosenColor, List.of(categoryId)))); } else { var configurationWithoutCategory = colorConfiguration.getConfigurations().stream() - .map(cc -> new ColorConfiguration(cc.getColorName(), cc.getCategories().stream().filter(c -> !c.equals(categoryId)).collect(toUnmodifiableList()))) - .filter(cc -> !cc.getCategories().isEmpty()) - .collect(toList()); + .map(cc -> new ColorConfiguration(cc.getColorName(), cc.getCategories().stream().filter(c -> !c.equals(categoryId)).toList())) + .filter(cc -> !cc.getCategories().isEmpty()).toList(); boolean colorExists = configurationWithoutCategory.stream().anyMatch(cc -> cc.getColorName().equals(chosenColor)); if(colorExists) { colorConfiguration = new CheckInOutputColorConfiguration(colorConfiguration.getDefaultColorName(), configurationWithoutCategory.stream().map(cc -> { - if(cc.getColorName().equals(chosenColor)) { + if (cc.getColorName().equals(chosenColor)) { var newList = new ArrayList<>(cc.getCategories()); newList.add(categoryId); return new ColorConfiguration(chosenColor, newList); } return cc; - }).collect(toUnmodifiableList())); + }).toList()); } else { var newList = new ArrayList<>(configurationWithoutCategory); newList.add(new ColorConfiguration(chosenColor, List.of(categoryId))); @@ -888,10 +977,11 @@ private int insertEvent(EventModification em) { String privateKey = UUID.randomUUID().toString(); ZoneId zoneId = ZoneId.of(em.getZoneId()); String currentVersion = flyway.info().current().getVersion().getVersion(); + var eventMetadata = requireNonNullElseGet(em.getMetadata(), AlfioMetadata::empty); return eventRepository.insert(em.getShortName(), em.getFormat(), em.getDisplayName(), em.getWebsiteUrl(), em.getExternalUrl(), em.getTermsAndConditionsUrl(), em.getPrivacyPolicyUrl(), em.getImageUrl(), em.getFileBlobId(), em.getLocation(), em.getLatitude(), em.getLongitude(), em.getBegin().toZonedDateTime(zoneId), em.getEnd().toZonedDateTime(zoneId), em.getZoneId(), em.getCurrency(), em.getAvailableSeats(), em.isVatIncluded(), - vat, paymentProxies, privateKey, em.getOrganizationId(), em.getLocales(), em.getVatStatus(), em.getPriceInCents(), currentVersion, Event.Status.DRAFT, em.getMetadata()).getKey(); + vat, paymentProxies, privateKey, em.getOrganizationId(), em.getLocales(), em.getVatStatus(), em.getPriceInCents(), currentVersion, Event.Status.DRAFT, eventMetadata).getKey(); } private String collectPaymentProxies(EventModification em) { @@ -934,12 +1024,14 @@ public void addPromoCode(String promoCode, String description, String emailReference, PromoCodeDiscount.CodeType codeType, - Integer hiddenCategoryId) { + Integer hiddenCategoryId, + String currencyCode) { Validate.isTrue(promoCode.length() >= 7, "min length is 7 chars"); Validate.isTrue((eventId != null && organizationId == null) || (eventId == null && organizationId != null), "eventId or organizationId must be not null"); Validate.isTrue(StringUtils.length(description) < 1025, "Description can be maximum 1024 chars"); Validate.isTrue(StringUtils.length(emailReference) < 257, "Description can be maximum 256 chars"); + Validate.isTrue(!PromoCodeDiscount.supportsCurrencyCode(codeType, discountType) || StringUtils.length(currencyCode) == 3, "Currency code is not valid"); if(maxUsage != null) { Validate.isTrue(maxUsage > 0, "Invalid max usage"); @@ -952,11 +1044,11 @@ public void addPromoCode(String promoCode, } if(PromoCodeDiscount.CodeType.ACCESS == codeType) { - Validate.isTrue(hiddenCategoryId != null, "Hidden category is required"); + Validate.notNull(hiddenCategoryId, "Hidden category is required"); } // - categoriesId = Optional.ofNullable(categoriesId).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).collect(toList()); + categoriesId = Optional.ofNullable(categoriesId).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).toList(); // if (organizationId == null) { @@ -967,7 +1059,8 @@ public void addPromoCode(String promoCode, discountType = DiscountType.NONE; } - promoCodeRepository.addPromoCode(promoCode, eventId, organizationId, start, end, discountAmount, discountType, Json.GSON.toJson(categoriesId), maxUsage, description, emailReference, codeType, hiddenCategoryId); + promoCodeRepository.addPromoCode(promoCode, eventId, organizationId, start, end, discountAmount, discountType, + Json.GSON.toJson(categoriesId), maxUsage, description, emailReference, codeType, hiddenCategoryId, currencyCode); } public void deletePromoCode(int promoCodeId) { @@ -984,12 +1077,12 @@ public void updatePromoCode(int promoCodeId, ZonedDateTime start, ZonedDateTime public List findPromoCodesInEvent(int eventId) { var event = eventRepository.findById(eventId); - return promoCodeRepository.findAllInEvent(eventId).stream().map(p -> new PromoCodeDiscountWithFormattedTimeAndAmount(p, event.getZoneId(), event.getCurrency())).collect(toList()); + return promoCodeRepository.findAllInEvent(eventId).stream().map(p -> new PromoCodeDiscountWithFormattedTimeAndAmount(p, event.getZoneId(), event.getCurrency())).toList(); } public List findPromoCodesInOrganization(int organizationId) { ZoneId zoneId = ZoneId.systemDefault(); - return promoCodeRepository.findAllInOrganization(organizationId).stream().map(p -> new PromoCodeDiscountWithFormattedTimeAndAmount(p, zoneId, null)).collect(toList()); + return promoCodeRepository.findAllInOrganization(organizationId).stream().map(p -> new PromoCodeDiscountWithFormattedTimeAndAmount(p, zoneId, null)).toList(); } public String getEventUrl(Event event) { @@ -1011,7 +1104,7 @@ public List getPublishedEvents(SearchOptions searchOptions) { } public List getActiveEvents() { - return getActiveEventsStream().collect(toList()); + return getActiveEventsStream().toList(); } private Stream getActiveEventsStream() { @@ -1085,6 +1178,9 @@ public void deleteCategory(String eventName, int categoryId, String username) { throw new IllegalArgumentException("Event not found"); } int eventId = optionalEvent.get().getId(); + if(ticketCategoryRepository.countActiveByEventId(eventId) < 2) { + throw new IllegalArgumentException("At least one category is required"); + } var optionalCategory = getOptionalByIdAndActive(categoryId, eventId); if(optionalCategory.isEmpty()) { throw new IllegalArgumentException("Category not found"); @@ -1135,13 +1231,15 @@ public Map getEventsNameInOrganization(int orgId, Principal pri } public boolean updateMetadata(Event event, AlfioMetadata metadata) { + var existing = eventRepository.getMetadataForEvent(event.getId()); var updatedMetadata = extensionManager.handleMetadataUpdate(event, organizationRepository.getById(event.getOrganizationId()), metadata); - eventRepository.updateMetadata(Objects.requireNonNullElse(updatedMetadata, metadata), event.getId()); + eventRepository.updateMetadata(existing.merge(Objects.requireNonNullElse(updatedMetadata, metadata)), event.getId()); return true; } public boolean updateCategoryMetadata(EventAndOrganizationId event, int categoryId, AlfioMetadata metadata) { - return ticketCategoryRepository.updateMetadata(metadata, event.getId(), categoryId) == 1; + var existing = ticketCategoryRepository.getMetadata(event.getId(), categoryId); + return ticketCategoryRepository.updateMetadata(existing.merge(metadata), event.getId(), categoryId) == 1; } public AlfioMetadata getMetadataForEvent(EventAndOrganizationId event) { @@ -1172,5 +1270,13 @@ public Optional executeCapability(String eventName, }); } + public List getLinkedSubscriptionIds(int eventId, int organizationId) { + return subscriptionRepository.findLinkedSubscriptionIds(eventId, organizationId); + } + + public int getEventsCount() { + return eventRepository.countEvents(); + } + } diff --git a/src/main/java/alfio/manager/EventNameManager.java b/src/main/java/alfio/manager/EventNameManager.java index c6275e20ef..881de6c233 100644 --- a/src/main/java/alfio/manager/EventNameManager.java +++ b/src/main/java/alfio/manager/EventNameManager.java @@ -17,7 +17,6 @@ package alfio.manager; import alfio.repository.EventAdminRepository; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; @@ -34,7 +33,6 @@ import java.util.stream.IntStream; @Component -@AllArgsConstructor @Transactional(readOnly = true) public class EventNameManager { @@ -48,6 +46,10 @@ public class EventNameManager { .build(); private final EventAdminRepository eventAdminRepository; + public EventNameManager(EventAdminRepository eventAdminRepository) { + this.eventAdminRepository = eventAdminRepository; + } + /** * Generates and returns a short name based on the given display name.
    * The generated short name will be returned only if it was not already used.
    diff --git a/src/main/java/alfio/manager/EventStatisticsManager.java b/src/main/java/alfio/manager/EventStatisticsManager.java index 6cfdf96bb3..3444098789 100644 --- a/src/main/java/alfio/manager/EventStatisticsManager.java +++ b/src/main/java/alfio/manager/EventStatisticsManager.java @@ -25,7 +25,6 @@ import alfio.repository.*; import alfio.util.EventUtil; import alfio.util.MonetaryUtil; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -39,12 +38,10 @@ import java.util.stream.Stream; import static alfio.model.system.ConfigurationKeys.DISPLAY_STATS_IN_EVENT_DETAIL; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import static org.apache.commons.lang3.ObjectUtils.firstNonNull; @Component -@AllArgsConstructor @Transactional(readOnly = true) public class EventStatisticsManager { @@ -60,14 +57,38 @@ public class EventStatisticsManager { private final SubscriptionRepository subscriptionRepository; private final ExtensionManager extensionManager; + public EventStatisticsManager(EventRepository eventRepository, + EventDescriptionRepository eventDescriptionRepository, + TicketSearchRepository ticketSearchRepository, + TicketCategoryRepository ticketCategoryRepository, + TicketCategoryDescriptionRepository ticketCategoryDescriptionRepository, + TicketReservationRepository ticketReservationRepository, + SpecialPriceRepository specialPriceRepository, + ConfigurationManager configurationManager, + UserManager userManager, + SubscriptionRepository subscriptionRepository, + ExtensionManager extensionManager) { + this.eventRepository = eventRepository; + this.eventDescriptionRepository = eventDescriptionRepository; + this.ticketSearchRepository = ticketSearchRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketCategoryDescriptionRepository = ticketCategoryDescriptionRepository; + this.ticketReservationRepository = ticketReservationRepository; + this.specialPriceRepository = specialPriceRepository; + this.configurationManager = configurationManager; + this.userManager = userManager; + this.subscriptionRepository = subscriptionRepository; + this.extensionManager = extensionManager; + } + private List getAllEvents(String username) { - List orgIds = userManager.findUserOrganizations(username).stream().map(Organization::getId).collect(toList()); + List orgIds = userManager.findUserOrganizations(username).stream().map(Organization::getId).toList(); return orgIds.isEmpty() ? Collections.emptyList() : eventRepository.findByOrganizationIds(orgIds); } public List getAllEventsWithStatisticsFilteredBy(String username, Predicate predicate) { - List events = getAllEvents(username).stream().filter(predicate).collect(toList()); + List events = getAllEvents(username).stream().filter(predicate).toList(); Map mappedEvent = events.stream().collect(Collectors.toMap(Event::getId, Function.identity())); if(!mappedEvent.isEmpty()) { boolean isOwner = userManager.isOwner(userManager.findUserByUsername(username)); @@ -81,7 +102,7 @@ public List getAllEventsWithStatisticsFilteredBy(String username return stats.map(stat -> { Event event = mappedEvent.get(stat.getEventId()); return new EventStatistic(event, stat, displayStatisticsForEvent(event)); - }).collect(Collectors.toList()); + }).toList(); } else { return Collections.emptyList(); } @@ -105,7 +126,7 @@ public EventWithAdditionalInfo getEventWithAdditionalInfo(String eventName, Stri BigDecimal grossIncome = owner ? MonetaryUtil.centsToUnit(eventRepository.getGrossIncome(event.getId()), event.getCurrency()) : BigDecimal.ZERO; List ticketCategories = ticketCategoryRepository.findAllTicketCategories(event.getId()); - List ticketCategoriesIds = ticketCategories.stream().map(TicketCategory::getId).collect(Collectors.toList()); + List ticketCategoriesIds = ticketCategories.stream().map(TicketCategory::getId).toList(); Map> descriptions = ticketCategoryDescriptionRepository.descriptionsByTicketCategory(ticketCategoriesIds); Map ticketCategoriesStatistics = owner ? ticketCategoryRepository.findStatisticsForEventIdByCategoryId(event.getId()) : ticketCategoriesIds.stream().collect(toMap(Function.identity(), id -> TicketCategoryStatisticView.empty(id, event.getId()))); @@ -115,7 +136,7 @@ public EventWithAdditionalInfo getEventWithAdditionalInfo(String eventName, Stri List tWithInfo = ticketCategories.stream() .map(t -> new TicketCategoryWithAdditionalInfo(event, t, ticketCategoriesStatistics.get(t.getId()), descriptions.get(t.getId()), specialPrices.get(t.getId()), metadata.get(t.getId()))) - .collect(Collectors.toList()); + .toList(); Set supportedCapabilities; if(event.getFormat() != Event.EventFormat.IN_PERSON) { @@ -124,6 +145,8 @@ public EventWithAdditionalInfo getEventWithAdditionalInfo(String eventName, Stri supportedCapabilities = Set.of(); } + // TODO category and event settings + return new EventWithAdditionalInfo(event, tWithInfo, eventStatistic, diff --git a/src/main/java/alfio/manager/ExportManager.java b/src/main/java/alfio/manager/ExportManager.java new file mode 100644 index 0000000000..bf1845d9bf --- /dev/null +++ b/src/main/java/alfio/manager/ExportManager.java @@ -0,0 +1,60 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager; + +import alfio.manager.user.UserManager; +import alfio.model.ReservationsByEvent; +import alfio.model.user.Organization; +import alfio.repository.ExportRepository; +import alfio.util.ClockProvider; +import org.springframework.stereotype.Component; + +import java.security.Principal; +import java.time.LocalDate; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Component +public class ExportManager { + + private final ExportRepository exportRepository; + private final ClockProvider clockProvider; + private final UserManager userManager; + + public ExportManager(ExportRepository exportRepository, + ClockProvider clockProvider, + UserManager userManager) { + this.exportRepository = exportRepository; + this.clockProvider = clockProvider; + this.userManager = userManager; + } + + public List reservationsForInterval(LocalDate from, LocalDate to, Principal principal) { + if (from.isAfter(to)) { + throw new IllegalArgumentException("Wrong interval"); + } + var orgIds = userManager.findUserOrganizations(Objects.requireNonNull(principal).getName()); + if (orgIds.isEmpty()) { + throw new IllegalArgumentException("Wrong user"); + } + var zoneId = clockProvider.getClock().getZone(); + var zonedFrom = from.atStartOfDay().atZone(zoneId); + var zonedTo = to.plusDays(1).atStartOfDay().minusSeconds(1).atZone(zoneId); + return exportRepository.allReservationsForInterval(zonedFrom, zonedTo, orgIds.stream().map(Organization::getId).collect(Collectors.toList())); + } +} diff --git a/src/main/java/alfio/manager/ExtensionManager.java b/src/main/java/alfio/manager/ExtensionManager.java index d5931bafd8..14fcfe7c11 100644 --- a/src/main/java/alfio/manager/ExtensionManager.java +++ b/src/main/java/alfio/manager/ExtensionManager.java @@ -18,6 +18,7 @@ package alfio.manager; import alfio.config.authentication.support.OpenIdAlfioAuthentication; +import alfio.controller.form.ContactAndTicketsForm; import alfio.extension.ExtensionService; import alfio.extension.exception.AlfioScriptingException; import alfio.manager.payment.PaymentSpecification; @@ -30,21 +31,21 @@ import alfio.model.checkin.EventWithCheckInInfo; import alfio.model.extension.*; import alfio.model.metadata.AlfioMetadata; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.metadata.TicketMetadata; import alfio.model.metadata.TicketMetadataContainer; +import alfio.model.subscription.Subscription; +import alfio.model.subscription.SubscriptionDescriptor; import alfio.model.system.ConfigurationKeys; import alfio.model.user.Organization; import alfio.model.user.PublicUserProfile; import alfio.model.user.User; -import alfio.repository.EventRepository; -import alfio.repository.TicketRepository; -import alfio.repository.TicketReservationRepository; -import alfio.repository.TransactionRepository; +import alfio.repository.*; import alfio.util.ClockProvider; import alfio.util.EventUtil; import alfio.util.MonetaryUtil; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.validation.BindingResult; @@ -55,16 +56,18 @@ import java.nio.file.Paths; import java.time.ZonedDateTime; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import static alfio.extension.ExtensionService.toPath; import static alfio.manager.support.extension.ExtensionEvent.*; import static alfio.model.PromoCodeDiscount.DiscountType.PERCENTAGE; @Component -@AllArgsConstructor -@Log4j2 public class ExtensionManager { + private static final Logger log = LoggerFactory.getLogger(ExtensionManager.class); + private static final String TICKET = "ticket"; private static final String EVENT_METADATA = "eventMetadata"; private static final String ORGANIZATION = "organization"; @@ -83,6 +86,23 @@ public class ExtensionManager { private final TicketRepository ticketRepository; private final ConfigurationManager configurationManager; private final TransactionRepository transactionRepository; + private final TicketCategoryRepository ticketCategoryRepository; + + public ExtensionManager(ExtensionService extensionService, + EventRepository eventRepository, + TicketReservationRepository ticketReservationRepository, + TicketRepository ticketRepository, + ConfigurationManager configurationManager, + TransactionRepository transactionRepository, + TicketCategoryRepository ticketCategoryRepository) { + this.extensionService = extensionService; + this.eventRepository = eventRepository; + this.ticketReservationRepository = ticketReservationRepository; + this.ticketRepository = ticketRepository; + this.configurationManager = configurationManager; + this.transactionRepository = transactionRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + } boolean isSupported(ExtensionCapability extensionCapability, PurchaseContext purchaseContext) { @@ -153,8 +173,8 @@ public void handleTicketAssignment(Ticket ticket, event, Map.of( TICKET, ticket, - ADDITIONAL_INFO, additionalInfo, - EVENT_METADATA, eventRepository.getMetadataForEvent(event.getId()), + ADDITIONAL_INFO, Objects.requireNonNullElse(additionalInfo, Map.of()), + EVENT_METADATA, Objects.requireNonNullElseGet(eventRepository.getMetadataForEvent(event.getId()), AlfioMetadata::empty), "onlineAccessTicket", EventUtil.isAccessOnline(category, event) )); } @@ -193,7 +213,7 @@ void handleStuckReservations(Event event, List stuckReservationsId) { asyncCall(ExtensionEvent.STUCK_RESERVATIONS, event, payload); } - Optional handleReservationEmailCustomText(PurchaseContext purchaseContext, TicketReservation reservation, TicketReservationAdditionalInfo additionalInfo) { + public Optional handleReservationEmailCustomText(PurchaseContext purchaseContext, TicketReservation reservation, TicketReservationAdditionalInfo additionalInfo) { Map payload = Map.of( RESERVATION, reservation, "purchaseContext", purchaseContext, @@ -255,7 +275,7 @@ public Optional handleInvoiceGeneration(PaymentSpecification payload.put("vatNr", billingDetails.getTaxId()); payload.put("vatStatus", spec.getVatStatus()); - return Optional.ofNullable(syncCall(ExtensionEvent.INVOICE_GENERATION, spec.getPurchaseContext(), payload, InvoiceGeneration.class)); + return Optional.ofNullable(syncCall(ExtensionEvent.INVOICE_GENERATION, spec.getPurchaseContext(), payload, InvoiceGeneration.class, false)); } public Optional handleCreditNoteGeneration(PurchaseContext purchaseContext, @@ -347,8 +367,8 @@ void handleReservationsCreditNoteIssuedForEvent(Event event, List reserv void handleRefund(PurchaseContext purchaseContext, TicketReservation reservation, TransactionAndPaymentInfo info) { Map payload = new HashMap<>(); payload.put(RESERVATION, reservation); - payload.put("transaction", info.getTransaction()); - payload.put("paymentInfo", info.getPaymentInformation()); + payload.put("transaction", info.transaction()); + payload.put("paymentInfo", info.paymentInformation()); asyncCall(ExtensionEvent.REFUND_ISSUED, purchaseContext, payload); } @@ -381,7 +401,7 @@ public boolean handlePdfTransformation(String html, PurchaseContext purchaseCont if(response == null || response.isEmpty()) { return false; } - Path tempFilePath = Paths.get(response.getTempFilePath()); + Path tempFilePath = Paths.get(response.tempFilePath()); if(Files.exists(tempFilePath)) { Files.copy(tempFilePath, outputStream); Files.delete(tempFilePath); @@ -422,7 +442,7 @@ public Optional handleDynamicDiscount(Event event, Map handleTicketAssignmentMetadata(TicketWithMetadat context.put(TICKET_METADATA, ticketWithMetadata.getMetadata().getMetadataForKey(TicketMetadataContainer.GENERAL).orElseGet(TicketMetadata::empty)); return Optional.ofNullable(syncCall(ExtensionEvent.TICKET_ASSIGNED_GENERATE_METADATA, event, context, TicketMetadata.class, false)); } + + public Optional handleSubscriptionAssignmentMetadata(Subscription subscription, + SubscriptionDescriptor descriptor, + SubscriptionMetadata subscriptionMetadata) { + var context = new HashMap(); + context.put("subscription", subscription); + context.put("metadata", Objects.requireNonNullElseGet(subscriptionMetadata, SubscriptionMetadata::empty)); + context.put("subscriptionDescriptor", descriptor); + return Optional.ofNullable(syncCall(ExtensionEvent.SUBSCRIPTION_ASSIGNED_GENERATE_METADATA, descriptor, context, SubscriptionMetadata.class, false)); + } + + public Optional handleCustomTaxPolicy(PurchaseContext purchaseContext, + String reservationId, + ContactAndTicketsForm form, + TotalPrice reservationCost) { + if (!purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) || !reservationCost.requiresPayment()) { + return Optional.empty(); + } + var event = (Event) purchaseContext; + var categoriesById = ticketCategoryRepository.findCategoriesInReservation(reservationId).stream() + .collect(Collectors.toMap(TicketCategory::getId, Function.identity())); + var ticketInfoById = ticketRepository.findBasicTicketInfoForReservation(event.getId(), reservationId).stream() + .collect(Collectors.toMap(TicketInfo::getTicketUuid, Function.identity())); + var context = new HashMap(); + context.put(EVENT, event); + context.put(RESERVATION_ID, reservationId); + context.put("reservationForm", form); + context.put("categoriesById", categoriesById); + context.put("ticketInfoByUuid", ticketInfoById); + return Optional.ofNullable(syncCall(CUSTOM_TAX_POLICY_APPLICATION, event, context, CustomTaxPolicy.class, false)); + } } diff --git a/src/main/java/alfio/manager/FileDownloadManager.java b/src/main/java/alfio/manager/FileDownloadManager.java index 216d268a32..ec4263d0ee 100644 --- a/src/main/java/alfio/manager/FileDownloadManager.java +++ b/src/main/java/alfio/manager/FileDownloadManager.java @@ -17,22 +17,23 @@ package alfio.manager; import alfio.model.modification.UploadBase64FileModification; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.util.Arrays; import java.util.Objects; import java.util.regex.Pattern; -@Log4j2 public class FileDownloadManager { + private static final Logger log = LoggerFactory.getLogger(FileDownloadManager.class); + private final HttpClient httpClient; public FileDownloadManager(HttpClient httpClient) { @@ -41,7 +42,7 @@ public FileDownloadManager(HttpClient httpClient) { public DownloadedFile downloadFile(String url) { HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(url)).GET().build(); - HttpResponse response = null; + HttpResponse response; try { response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray()); } catch (IOException exception) { @@ -55,7 +56,7 @@ public DownloadedFile downloadFile(String url) { if(callSuccessful(response)) { String[] parts = Pattern.compile("/").split(url); String name = parts[parts.length - 1]; - if(Objects.nonNull(response.body()) && response.body().length <= FileUploadManager.MAXIMUM_ALLOWED_SIZE) { + if(Objects.nonNull(response.body())) { return new DownloadedFile( response.body(), name, @@ -65,7 +66,7 @@ public DownloadedFile downloadFile(String url) { return null; } } else { - log.warn("downloading file not successful:" + response); + log.warn("downloading file not successful: {}", response); return null; } } @@ -78,12 +79,8 @@ private boolean callSuccessful(HttpResponse response) { return response.statusCode() >= 200 && response.statusCode() < 300; } - @Getter - @AllArgsConstructor - public static class DownloadedFile { - private byte[] file; - private String name; - private String type; + + public record DownloadedFile(byte[] file, String name, String type) { public UploadBase64FileModification toUploadBase64FileModification() { UploadBase64FileModification uf = new UploadBase64FileModification(); @@ -92,6 +89,33 @@ public UploadBase64FileModification toUploadBase64FileModification() { uf.setType(type); return uf; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DownloadedFile df)) { + return false; + } + return Arrays.equals(file, df.file) && name.equals(df.name) && type.equals(df.type); + } + + @Override + public int hashCode() { + int result = Objects.hash(name, type); + result = 31 * result + Arrays.hashCode(file); + return result; + } + + @Override + public String toString() { + return "DownloadedFile{" + + "file=" + Arrays.toString(file) + + ", name='" + name + '\'' + + ", type='" + type + '\'' + + '}'; + } } } diff --git a/src/main/java/alfio/manager/FileUploadManager.java b/src/main/java/alfio/manager/FileUploadManager.java index 8bf27f5dab..888f271558 100644 --- a/src/main/java/alfio/manager/FileUploadManager.java +++ b/src/main/java/alfio/manager/FileUploadManager.java @@ -22,42 +22,61 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.RemovalCause; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; +import com.github.benmanes.caffeine.cache.RemovalListener; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.imgscalr.Scalr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MimeType; +import org.springframework.util.MimeTypeUtils; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; +import java.nio.file.Files; import java.time.Duration; import java.util.*; @Component @Transactional -@Log4j2 -@RequiredArgsConstructor public class FileUploadManager { + static final int IMAGE_THUMB_MAX_WIDTH_PX = 300; + static final int IMAGE_THUMB_MAX_HEIGHT_PX = 200; + private static final Logger log = LoggerFactory.getLogger(FileUploadManager.class); /** * Maximum allowed file size is 200kb */ - static final int MAXIMUM_ALLOWED_SIZE = 1024 * 200; + private static final int MAXIMUM_ALLOWED_SIZE = 1024 * 200; + private static final MimeType IMAGE_TYPE = MimeType.valueOf("image/*"); private final FileUploadRepository repository; private final Cache cache = Caffeine.newBuilder() .maximumSize(20) .expireAfterWrite(Duration.ofMinutes(20)) - .removalListener((String key, File value, RemovalCause cause) -> { - if(value != null) { - boolean result = value.delete(); - log.trace("deleted {}: {}", key, result); - } - }) + .removalListener(removalListener()) .build(); + public FileUploadManager(FileUploadRepository repository) { + this.repository = repository; + } + + private static RemovalListener removalListener() { + return (String key, File value, RemovalCause cause) -> { + if (value != null) { + try { + Files.delete(value.toPath()); + log.trace("deleted {}", key); + } catch(Exception ex) { + log.trace("Error while deleting file", ex); + } + } + }; + } + public Optional findMetadata(String id) { return repository.findById(id); } @@ -79,12 +98,13 @@ public void outputFile(String id, OutputStream out) { } } - public String insertFile(UploadBase64FileModification file) { - Validate.exclusiveBetween(1, MAXIMUM_ALLOWED_SIZE, file.getFile().length); - String digest = DigestUtils.sha256Hex(file.getFile()); + final var mimeType = MimeTypeUtils.parseMimeType(file.getType()); + var upload = resizeIfNeeded(file, mimeType); + Validate.exclusiveBetween(1, MAXIMUM_ALLOWED_SIZE, upload.getFile().length); + String digest = DigestUtils.sha256Hex(upload.getFile()); if (Integer.valueOf(0).equals(repository.isPresent(digest))) { - repository.upload(file, digest, getAttributes(file)); + repository.upload(upload, digest, getAttributes(upload)); } return digest; } @@ -94,6 +114,35 @@ public void cleanupUnreferencedBlobFiles(Date date) { log.debug("removed {} unused file_blob", deleted); } + /** + * @author Etienne M. + */ + private UploadBase64FileModification resizeIfNeeded(UploadBase64FileModification upload, MimeType mimeType) { + if (!mimeType.isCompatibleWith(IMAGE_TYPE)) { + // not an image, nothing to do here. + return upload; + } + try { + BufferedImage image = ImageIO.read(new ByteArrayInputStream(upload.getFile())); + // resize only if the image is bigger than target size on either side + if (image.getWidth() > IMAGE_THUMB_MAX_WIDTH_PX || image.getHeight() > IMAGE_THUMB_MAX_HEIGHT_PX) { + UploadBase64FileModification resized = new UploadBase64FileModification(); + BufferedImage thumbImg = Scalr.resize(image, Scalr.Method.QUALITY, Scalr.Mode.AUTOMATIC, IMAGE_THUMB_MAX_WIDTH_PX, IMAGE_THUMB_MAX_HEIGHT_PX, Scalr.OP_ANTIALIAS); + try (final var baos = new ByteArrayOutputStream()) { + ImageIO.write(thumbImg, mimeType.getSubtype(), baos); + resized.setFile(baos.toByteArray()); + } + resized.setAttributes(upload.getAttributes()); + resized.setName(upload.getName()); + resized.setType(upload.getType()); + return resized; + } + return upload; + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + private Map getAttributes(UploadBase64FileModification file) { if(!StringUtils.startsWith(file.getType(), "image/")) { return Collections.emptyMap(); diff --git a/src/main/java/alfio/manager/GroupManager.java b/src/main/java/alfio/manager/GroupManager.java index 25e41dcae7..cc89a03017 100644 --- a/src/main/java/alfio/manager/GroupManager.java +++ b/src/main/java/alfio/manager/GroupManager.java @@ -30,11 +30,11 @@ import alfio.repository.GroupRepository; import alfio.repository.TicketRepository; import ch.digitalfondue.npjt.AffectedRowCountAndKey; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; @@ -49,11 +49,13 @@ import static alfio.model.group.LinkedGroup.MatchType.FULL; import static alfio.model.group.LinkedGroup.Type.*; import static java.util.Collections.singletonList; +import static org.apache.commons.text.StringEscapeUtils.escapeHtml4; @Component -@Log4j2 public class GroupManager { + private static final Logger log = LoggerFactory.getLogger(GroupManager.class); + private final GroupRepository groupRepository; private final TicketRepository ticketRepository; private final AuditingRepository auditingRepository; @@ -81,7 +83,7 @@ public Result createNew(GroupModification input) { } Group createNew(String name, String description, int organizationId) { - AffectedRowCountAndKey insert = groupRepository.insert(name, description, organizationId); + AffectedRowCountAndKey insert = groupRepository.insert(escapeHtml4(name), escapeHtml4(description), organizationId); return groupRepository.getById(insert.getKey()); } @@ -130,7 +132,7 @@ public List getAllForOrganization(int organizationId) { public Optional loadComplete(int id) { return groupRepository.getOptionalById(id) .map(wl -> { - List items = groupRepository.getItems(wl.getId()).stream().map(i -> new GroupMemberModification(i.getId(), i.getValue(), i.getDescription())).collect(Collectors.toList()); + List items = groupRepository.getItems(wl.getId()).stream().map(i -> new GroupMemberModification(i.getId(), i.getValue(), i.getDescription())).toList(); return new GroupModification(wl.getId(), wl.getName(), wl.getDescription(), wl.getOrganizationId(), items); }); } @@ -164,7 +166,7 @@ public List findLinks(int eventId, int categoryId) { Result insertMembers(int groupId, List members) { Map> grouped = members.stream().collect(Collectors.groupingBy(GroupMemberModification::getValue)); - List duplicates = grouped.entrySet().stream().filter(e -> e.getValue().size() > 1).map(Map.Entry::getKey).collect(Collectors.toList()); + List duplicates = grouped.entrySet().stream().filter(e -> e.getValue().size() > 1).map(Map.Entry::getKey).toList(); return new Result.Builder() .checkPrecondition(duplicates::isEmpty, ErrorCode.lazy(() -> ErrorCode.custom("value.duplicate", duplicates.stream().limit(10).collect(Collectors.joining(", "))))) @@ -215,7 +217,7 @@ private Optional getMatchingMember(LinkedGroup configuration, Strin @Transactional public void deleteWhitelistedTicketsForReservation(String reservationId) { - List tickets = ticketRepository.findTicketsInReservation(reservationId).stream().map(Ticket::getId).collect(Collectors.toList()); + List tickets = ticketRepository.findTicketsInReservation(reservationId).stream().map(Ticket::getId).toList(); if(!tickets.isEmpty()) { int result = groupRepository.deleteExistingWhitelistedTickets(tickets); log.trace("deleted {} whitelisted tickets for reservation {}", result, reservationId); @@ -238,7 +240,7 @@ public Optional update(int listId, GroupModification modifica List notPresent = modification.getItems().stream() .filter(i -> i.getId() == null && !existingValues.contains(i.getValue().strip().toLowerCase())) .distinct() - .collect(Collectors.toList()); + .toList(); if(!notPresent.isEmpty()) { var insertResult = insertMembers(listId, notPresent); @@ -247,7 +249,7 @@ public Optional update(int listId, GroupModification modifica throw new DuplicateGroupItemException(error.getDescription()); } } - groupRepository.update(listId, modification.getName(), modification.getDescription()); + groupRepository.update(listId, escapeHtml4(modification.getName()), escapeHtml4(modification.getDescription())); return loadComplete(listId); } @@ -262,7 +264,7 @@ public boolean deactivateMembers(List memberIds, int groupId) { @Transactional public boolean deactivateGroup(int groupId) { - List members = groupRepository.getItems(groupId).stream().map(GroupMember::getId).collect(Collectors.toList()); + List members = groupRepository.getItems(groupId).stream().map(GroupMember::getId).toList(); if(!members.isEmpty()) { Validate.isTrue(deactivateMembers(members, groupId), "error while disabling group members"); } @@ -271,11 +273,9 @@ public boolean deactivateGroup(int groupId) { return true; } - @RequiredArgsConstructor - public static class WhitelistValidator implements Predicate { - private final int eventId; - private final GroupManager groupManager; + public record WhitelistValidator(int eventId, + GroupManager groupManager) implements Predicate { @Override public boolean test(WhitelistValidationItem item) { @@ -283,10 +283,7 @@ public boolean test(WhitelistValidationItem item) { } } - @RequiredArgsConstructor - public static class WhitelistValidationItem { - private final int categoryId; - private final String value; + public record WhitelistValidationItem(int categoryId, String value) { } public static class DuplicateGroupItemException extends RuntimeException { diff --git a/src/main/java/alfio/manager/NotificationManager.java b/src/main/java/alfio/manager/NotificationManager.java index af9c806d62..8783f46fef 100644 --- a/src/main/java/alfio/manager/NotificationManager.java +++ b/src/main/java/alfio/manager/NotificationManager.java @@ -26,6 +26,7 @@ import alfio.manager.system.Mailer; import alfio.model.*; import alfio.model.PurchaseContext.PurchaseContextType; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.subscription.SubscriptionDescriptor; import alfio.model.system.ConfigurationKeys; import alfio.model.user.Organization; @@ -34,10 +35,11 @@ import alfio.util.*; import com.fasterxml.jackson.core.type.TypeReference; import com.google.gson.*; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.security.crypto.codec.Hex; @@ -69,9 +71,10 @@ import static java.util.Objects.requireNonNullElseGet; @Component -@Log4j2 public class NotificationManager { + private static final Logger log = LoggerFactory.getLogger(NotificationManager.class); + private static final String EVENT_ID = "eventId"; private final Mailer mailer; private final MessageSourceManager messageSourceManager; @@ -104,7 +107,8 @@ public NotificationManager(Mailer mailer, AdditionalServiceItemRepository additionalServiceItemRepository, ExtensionManager extensionManager, ClockProvider clockProvider, - PurchaseContextManager purchaseContextManager) { + PurchaseContextManager purchaseContextManager, + SubscriptionRepository subscriptionRepository) { this.messageSourceManager = messageSourceManager; this.mailer = mailer; this.emailMessageRepository = emailMessageRepository; @@ -127,7 +131,8 @@ public NotificationManager(Mailer mailer, payload -> TemplateProcessor.buildCreditNotePdf(payload.getLeft(), fileUploadManager, payload.getMiddle(), templateManager, payload.getRight(), extensionManager))); attachmentTransformer.put(Mailer.AttachmentIdentifier.PASSBOOK, passKitManager::getPass); Function> retrieveFieldValues = EventUtil.retrieveFieldValues(ticketRepository, ticketFieldRepository, additionalServiceItemRepository); - attachmentTransformer.put(Mailer.AttachmentIdentifier.TICKET_PDF, generateTicketPDF(eventRepository, organizationRepository, configurationManager, fileUploadManager, templateManager, ticketReservationRepository, retrieveFieldValues, extensionManager, ticketRepository)); + attachmentTransformer.put(Mailer.AttachmentIdentifier.TICKET_PDF, generateTicketPDF(eventRepository, organizationRepository, configurationManager, fileUploadManager, templateManager, ticketReservationRepository, retrieveFieldValues, extensionManager, ticketRepository, subscriptionRepository)); + attachmentTransformer.put(Mailer.AttachmentIdentifier.SUBSCRIPTION_PDF, generateSubscriptionPDF(organizationRepository, configurationManager, fileUploadManager, templateManager, ticketReservationRepository, extensionManager, subscriptionRepository)); } private static Function, byte[]> generateTicketPDF(EventRepository eventRepository, @@ -138,7 +143,8 @@ private static Function, byte[]> generateTicketPDF(EventRepo TicketReservationRepository ticketReservationRepository, Function> retrieveFieldValues, ExtensionManager extensionManager, - TicketRepository ticketRepository) { + TicketRepository ticketRepository, + SubscriptionRepository subscriptionRepository) { return model -> { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Ticket ticket = Json.fromJson(model.get("ticket"), Ticket.class); @@ -148,11 +154,13 @@ private static Function, byte[]> generateTicketPDF(EventRepo Event event = eventRepository.findById(ticket.getEventId()); Organization organization = organizationRepository.getById(Integer.valueOf(model.get("organizationId"), 10)); var ticketWithMetadata = TicketWithMetadataAttributes.build(ticket, ticketRepository.getTicketMetadata(ticket.getId())); - TemplateProcessor.renderPDFTicket(LocaleUtil.forLanguageTag(ticket.getUserLanguage()), event, reservation, + var locale = LocaleUtil.forLanguageTag(ticket.getUserLanguage()); + TemplateProcessor.renderPDFTicket(locale, event, reservation, ticketWithMetadata, ticketCategory, organization, templateManager, fileUploadManager, - configurationManager.getShortReservationID(event, reservation), baos, retrieveFieldValues, extensionManager); + configurationManager.getShortReservationID(event, reservation), baos, retrieveFieldValues, extensionManager, + TemplateProcessor.getSubscriptionDetailsModelForTicket(ticket, subscriptionRepository::findDescriptorBySubscriptionId, locale)); } catch (IOException e) { - log.warn("was not able to generate ticket pdf for ticket with id" + ticket.getId(), e); + log.warn("was not able to generate ticket pdf for ticket with id {}", ticket.getId(), e); } return baos.toByteArray(); }; @@ -242,7 +250,7 @@ private static Function, byte[]> receiptOrInvoiceFactory(Pur reservationEmailModel.put("event", purchaseContext); if(receipt.isEmpty()) { - log.warn("was not able to generate the receipt for reservation id " + reservationId + " for locale " + language); + log.warn("was not able to generate the receipt for reservation id {} for locale {}", reservationId, language); } return receipt.orElse(null); }; @@ -258,6 +266,8 @@ public void sendTicketByEmail(Ticket ticket, Organization organization = organizationRepository.getById(event.getOrganizationId()); + boolean htmlEmailEnabled = configurationManager.getFor(ConfigurationKeys.ENABLE_HTML_EMAILS, event.getConfigurationLevel()) + .getValueAsBooleanOrDefault(); // pre-generate template in order to reuse model var renderedTemplate = textBuilder.generate(ticket); @@ -266,15 +276,15 @@ public void sendTicketByEmail(Ticket ticket, var attachmentModel = new HashMap(); // attachment model expects non-string properties to be JSON, so we convert them renderedTemplate.getSrcModel().forEach((k, v) -> { - if(v instanceof String) { - attachmentModel.put(k, (String) v); + if(v instanceof String s) { + attachmentModel.put(k, s); } else { attachmentModel.put(k, Json.toJson(v)); } }); attachments.add(CustomMessageManager.generateCalendarAttachmentForOnlineEvent(attachmentModel)); } else { - attachments.add(CustomMessageManager.generateTicketAttachment(ticket, reservation, ticketCategory, organization)); + attachments.add(CustomMessageManager.generateTicketAttachment(ticket, reservation, ticketCategory, organization, htmlEmailEnabled)); } String displayName = event.getDisplayName(); @@ -303,7 +313,7 @@ public List getCCForEventOrganizer(PurchaseContext purchaseContext) { .filter(Objects::nonNull) .map(String::trim) .filter(StringUtils::isNotBlank) - .collect(Collectors.toList()); + .toList(); } public void sendSimpleEmail(PurchaseContext event, String reservationId, String recipient, String subject, TemplateGenerator textBuilder) { @@ -427,8 +437,7 @@ private Mailer.Attachment[] decodeAttachments(String input) { Set alreadyPresents = Arrays.stream(attachments).map(Mailer.Attachment::getIdentifier).filter(Objects::nonNull).collect(Collectors.toSet()); // List toReinterpret = Arrays.stream(attachments) - .filter(attachment -> attachment.getIdentifier() != null && !attachment.getIdentifier().reinterpretAs().isEmpty()) - .collect(Collectors.toList()); + .filter(attachment -> attachment.getIdentifier() != null && !attachment.getIdentifier().reinterpretAs().isEmpty()).toList(); List generated = Arrays.stream(attachments) .map(attachment -> this.transformAttachment(attachment, attachment.getIdentifier())) @@ -443,7 +452,7 @@ private Mailer.Attachment[] decodeAttachments(String input) { ) ); - generated.addAll(reinterpreted.stream().filter(Objects::nonNull).collect(Collectors.toList())); + generated.addAll(reinterpreted.stream().filter(Objects::nonNull).toList()); return generated.toArray(new Mailer.Attachment[0]); } @@ -501,6 +510,40 @@ public Mailer.Attachment deserialize(JsonElement json, Type typeOfT, JsonDeseria } } + private static Function, byte[]> generateSubscriptionPDF(OrganizationRepository organizationRepository, + ConfigurationManager configurationManager, + FileUploadManager fileUploadManager, + TemplateManager templateManager, + TicketReservationRepository ticketReservationRepository, + ExtensionManager extensionManager, + SubscriptionRepository subscriptionRepository) { + return model -> { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + var subscriptionId = UUID.fromString(model.get("subscriptionId")); + var subscription = subscriptionRepository.findSubscriptionById(subscriptionId); + try { + var subscriptionDescriptor = subscriptionRepository.findDescriptorBySubscriptionId(subscriptionId); + var reservation = ticketReservationRepository.findReservationById(subscription.getReservationId()); + Organization organization = organizationRepository.getById(subscriptionDescriptor.getOrganizationId()); + var metadata = Objects.requireNonNullElseGet(subscriptionRepository.getSubscriptionMetadata(subscription.getId()), SubscriptionMetadata::empty); + TemplateProcessor.renderSubscriptionPDF(subscription, + LocaleUtil.forLanguageTag(reservation.getUserLanguage()), + subscriptionDescriptor, + reservation, + metadata, + organization, + templateManager, + fileUploadManager, + configurationManager.getShortReservationID(subscriptionDescriptor, reservation), + baos, + extensionManager); + } catch (IOException e) { + log.warn("was not able to generate subscription pdf for " + subscription.getId(), e); + } + return baos.toByteArray(); + }; + } + private static String purchaseContextCacheKey(EmailMessage message) { return message.getPurchaseContextType() + "//" + requireNonNullElse(message.getEventId(), message.getSubscriptionDescriptorId()); diff --git a/src/main/java/alfio/manager/OrganizationDeleter.java b/src/main/java/alfio/manager/OrganizationDeleter.java new file mode 100644 index 0000000000..7207203744 --- /dev/null +++ b/src/main/java/alfio/manager/OrganizationDeleter.java @@ -0,0 +1,75 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager; + +import alfio.repository.*; +import alfio.repository.user.OrganizationRepository; +import alfio.repository.user.join.UserOrganizationRepository; +import alfio.util.RequestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.security.Principal; +import java.util.List; + +@Component +@Transactional +public class OrganizationDeleter { + + private static final Logger log = LoggerFactory.getLogger(OrganizationDeleter.class); + + private final UserOrganizationRepository userOrganizationRepository; + private final OrganizationRepository organizationRepository; + private final EventRepository eventRepository; + private final EventDeleterRepository eventDeleterRepository; + private final OrganizationDeleterRepository organizationDeleterRepository; + + public OrganizationDeleter(UserOrganizationRepository userOrganizationRepository, + OrganizationRepository organizationRepository, + EventRepository eventRepository, + EventDeleterRepository eventDeleterRepository, + OrganizationDeleterRepository organizationDeleterRepository) { + this.userOrganizationRepository = userOrganizationRepository; + this.organizationRepository = organizationRepository; + this.eventRepository = eventRepository; + this.eventDeleterRepository = eventDeleterRepository; + this.organizationDeleterRepository = organizationDeleterRepository; + } + + + public boolean deleteOrganization(int organizationId, Principal principal) { + boolean isAdmin = RequestUtils.isAdmin(principal) || RequestUtils.isSystemApiKey(principal); + if (isAdmin) { + var originalOrg = organizationRepository.getById(organizationId); + log.warn("Delete organization {} ({}) initiated by user {}", organizationId, originalOrg.getName(), principal.getName()); + var disabledEventIds = eventRepository.disableEventsForOrganization(organizationId); + if (!disabledEventIds.isEmpty()) { + log.warn("deleting {} events linked to organization {}", disabledEventIds.size(), organizationId); + disabledEventIds.forEach(eventDeleterRepository::deleteAllForEvent); + } + int users = userOrganizationRepository.cleanupOrganization(organizationId); + log.warn("removed {} user(s) from organization {}", users, organizationId); + organizationDeleterRepository.deleteEmptyOrganizations(List.of(organizationId)); + return true; + } + return false; + } + + +} diff --git a/src/main/java/alfio/manager/PassKitManager.java b/src/main/java/alfio/manager/PassKitManager.java index 676ccf3145..3eac1170d9 100644 --- a/src/main/java/alfio/manager/PassKitManager.java +++ b/src/main/java/alfio/manager/PassKitManager.java @@ -17,6 +17,7 @@ package alfio.manager; import alfio.manager.system.ConfigurationManager; +import alfio.manager.system.Mailer; import alfio.model.*; import alfio.model.system.ConfigurationKeys; import alfio.model.user.Organization; @@ -24,6 +25,7 @@ import alfio.repository.user.OrganizationRepository; import alfio.util.Json; import alfio.util.LocaleUtil; +import alfio.util.MustacheCustomTag; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.ryantenney.passkit4j.Pass; @@ -33,10 +35,12 @@ import com.ryantenney.passkit4j.sign.PassSigner; import com.ryantenney.passkit4j.sign.PassSignerImpl; import com.ryantenney.passkit4j.sign.PassSigningException; -import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.tuple.Pair; import org.imgscalr.Scalr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; @@ -52,10 +56,10 @@ import static alfio.model.system.ConfigurationKeys.*; @Component -@AllArgsConstructor -@Log4j2 public class PassKitManager { + private static final Logger log = LoggerFactory.getLogger(PassKitManager.class); + private static final String APPLE_PASS = "ApplePass"; private final Cache> passKitLogoCache = Caffeine.newBuilder() .maximumSize(20) @@ -68,7 +72,22 @@ public class PassKitManager { private final EventDescriptionRepository eventDescriptionRepository; private final TicketCategoryRepository ticketCategoryRepository; private final TicketRepository ticketRepository; - private final TicketReservationRepository ticketReservationRepository; + + public PassKitManager(EventRepository eventRepository, + OrganizationRepository organizationRepository, + ConfigurationManager configurationManager, + FileUploadManager fileUploadManager, + EventDescriptionRepository eventDescriptionRepository, + TicketCategoryRepository ticketCategoryRepository, + TicketRepository ticketRepository) { + this.eventRepository = eventRepository; + this.organizationRepository = organizationRepository; + this.configurationManager = configurationManager; + this.fileUploadManager = fileUploadManager; + this.eventDescriptionRepository = eventDescriptionRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketRepository = ticketRepository; + } public boolean writePass(Ticket ticket, EventAndOrganizationId event, OutputStream out) throws IOException, PassSigningException { @@ -85,6 +104,10 @@ public boolean writePass(Ticket ticket, EventAndOrganizationId event, OutputStre byte[] getPass(Map model) { try { + if (BooleanUtils.TRUE.equals(model.get(Mailer.SKIP_PASSBOOK))) { + log.trace("HTML email enabled. Skipping passbook generation"); + return null; + } Ticket ticket = Json.fromJson(model.get("ticket"), Ticket.class); int eventId = ticket.getEventId(); Event event = eventRepository.findById(eventId); @@ -150,7 +173,8 @@ private void buildPass(Ticket ticket, String privateKeyAlias = config.get(PASSBOOK_PRIVATE_KEY_ALIAS); - String eventDescription = eventDescriptionRepository.findDescriptionByEventIdTypeAndLocale(event.getId(), EventDescription.EventDescriptionType.DESCRIPTION, ticket.getUserLanguage()).orElse(""); + String eventDescription = MustacheCustomTag.renderToTextCommonmark( + eventDescriptionRepository.findDescriptionByEventIdTypeAndLocale(event.getId(), EventDescription.EventDescriptionType.DESCRIPTION, ticket.getUserLanguage()).orElse("")); TicketCategory category = ticketCategoryRepository.getById(ticket.getCategoryId()); var ticketValidityStart = Optional.ofNullable(category.getTicketValidityStart(event.getZoneId())).orElse(event.getBegin()); Pass pass = new Pass() @@ -165,7 +189,7 @@ private void buildPass(Ticket ticket, .relevantDate(Date.from(ticketValidityStart.toInstant())) .expirationDate(Date.from(Optional.ofNullable(category.getTicketValidityEnd(event.getZoneId())).orElse(event.getEnd()).toInstant())) - .barcode(new Barcode(BarcodeFormat.QR, ticket.ticketCode(event.getPrivateKey()))) + .barcode(new Barcode(BarcodeFormat.QR, ticket.ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive()))) .labelColor(Color.BLACK) .foregroundColor(Color.BLACK) .backgroundColor(Color.WHITE) @@ -213,7 +237,7 @@ private void buildPass(Ticket ticket, }); pass.files(passResources.toArray(new PassResource[0])); - try(InputStream appleCert = new ClassPathResource("/alfio/certificates/AppleWWDRCA.cer").getInputStream()) { + try(InputStream appleCert = new ClassPathResource("/alfio/certificates/AppleWWDRCAG4.cer").getInputStream()) { PassSigner signer = PassSignerImpl.builder() .keystore(new ByteArrayInputStream(keystoreRaw), keystorePwd) .alias(privateKeyAlias) @@ -228,6 +252,14 @@ private String buildAuthenticationToken(Ticket ticket, EventAndOrganizationId ev return Ticket.hmacSHA256Base64(privateKey, code); } + public Optional> retrieveTicketDetails(String eventName, String ticketUuid) { + return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) + .flatMap(e -> ticketRepository.findOptionalByUUID(ticketUuid) + .filter(t -> e.getId() == t.getEventId()) + .map(t -> Pair.of(e, t)) + ); + } + public Optional> validateToken(String eventName, String typeIdentifier, String ticketUuid, String authorizationHeader) { String token; if(authorizationHeader.startsWith(APPLE_PASS)) { diff --git a/src/main/java/alfio/manager/PaymentManager.java b/src/main/java/alfio/manager/PaymentManager.java index 7815460d75..fb0a0d6bf1 100644 --- a/src/main/java/alfio/manager/PaymentManager.java +++ b/src/main/java/alfio/manager/PaymentManager.java @@ -29,24 +29,28 @@ import alfio.repository.AuditingRepository; import alfio.repository.TransactionRepository; import alfio.repository.user.UserRepository; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import java.security.Principal; +import java.time.ZonedDateTime; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.Objects.requireNonNullElse; + @Component -@Log4j2 -@AllArgsConstructor public class PaymentManager { public static final String PAYMENT_TOKEN = "PAYMENT_TOKEN"; + private static final Logger log = LoggerFactory.getLogger(PaymentManager.class); + private final TransactionRepository transactionRepository; private final ConfigurationManager configurationManager; private final AuditingRepository auditingRepository; @@ -55,6 +59,20 @@ public class PaymentManager { private final List paymentProviders; // injected by Spring + public PaymentManager(TransactionRepository transactionRepository, + ConfigurationManager configurationManager, + AuditingRepository auditingRepository, + UserRepository userRepository, + ExtensionManager extensionManager, + List paymentProviders) { + this.transactionRepository = transactionRepository; + this.configurationManager = configurationManager; + this.auditingRepository = auditingRepository; + this.userRepository = userRepository; + this.extensionManager = extensionManager; + this.paymentProviders = paymentProviders; + } + public Optional lookupProviderByTransactionAndCapabilities(Transaction transaction, List> capabilities) { return paymentProviders.stream() .filter(filterByCapabilities(capabilities)) @@ -85,22 +103,27 @@ List>> validateSelection(List> proxiesByMethod = paymentProxies.stream() - .flatMap(proxy -> streamActiveProvidersByProxy(proxy, paymentContext)) + .flatMap(proxy -> streamProvidersByProxyAndCapabilities(proxy, List.of())) .map(provider -> Pair.of(provider.getPaymentProxy(), provider.getSupportedPaymentMethods(paymentContext, TransactionRequest.empty()))) .flatMap(pair -> pair.getValue().stream().map(pm -> Pair.of(pm, pair.getKey()))) // flip .collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toSet()))); return proxiesByMethod.entrySet().stream() .filter(e -> e.getValue().size() > 1) - .collect(Collectors.toList()); + .toList(); + } + + private Stream streamProvidersByProxyAndCapabilities(PaymentProxy paymentProxy, + List> capabilities) { + return paymentProviders.stream() + .filter(pp -> pp.getPaymentProxy() == paymentProxy) + .filter(filterByCapabilities(capabilities)); } Stream streamActiveProvidersByProxyAndCapabilities(PaymentProxy paymentProxy, PaymentContext paymentContext, List> capabilities) { - return paymentProviders.stream() - .filter(pp -> pp.getPaymentProxy() == paymentProxy && pp.isActive(paymentContext)) - .filter(filterByCapabilities(capabilities)); + return streamProvidersByProxyAndCapabilities(paymentProxy, capabilities).filter((pp) -> pp.isActive(paymentContext)); } private static Predicate filterByCapabilities(List> capabilities) { @@ -119,7 +142,7 @@ private List getPaymentMethods(PaymentContext context, Transac .filter(p -> !blacklist.contains(p.getKey())) .map(proxy -> Pair.of(proxy, paymentMethodsByProxy(context, transactionRequest, proxy))) .flatMap(pair -> pair.getRight().stream().map(pm -> new PaymentMethodDTO(pair.getLeft(), pm, PaymentMethodDTO.PaymentMethodStatus.ACTIVE))) - .collect(Collectors.toList()); + .toList(); } private Set paymentMethodsByProxy(PaymentContext context, TransactionRequest transactionRequest, PaymentProxy proxy) { @@ -164,14 +187,14 @@ Audit.EventType.REFUND_ATTEMPT_FAILED, new Date(), Audit.EntityType.RESERVATION, return res; } - TransactionAndPaymentInfo getInfo(TicketReservation reservation, PurchaseContext purchaseContext) { + public TransactionAndPaymentInfo getInfo(TicketReservation reservation, PurchaseContext purchaseContext) { Optional maybeTransaction = transactionRepository.loadOptionalByReservationId(reservation.getId()) .map(transaction -> internalGetInfo(reservation, purchaseContext, transaction)); maybeTransaction.ifPresent(info -> { try { - Transaction transaction = info.getTransaction(); + Transaction transaction = info.transaction(); String transactionId = transaction.getTransactionId(); - PaymentInformation paymentInformation = info.getPaymentInformation(); + PaymentInformation paymentInformation = info.paymentInformation(); if(paymentInformation != null && feesUpdated(transaction, paymentInformation)) { transactionRepository.updateFees(transactionId, reservation.getId(), safeParseLong(paymentInformation.getPlatformFee()), safeParseLong(paymentInformation.getFee())); } @@ -182,6 +205,19 @@ TransactionAndPaymentInfo getInfo(TicketReservation reservation, PurchaseContext return maybeTransaction.orElseGet(() -> new TransactionAndPaymentInfo(reservation.getPaymentMethod(),null, new PaymentInformation(reservation.getPaidAmount(), null, null, null))); } + public void updateTransactionDetails(String reservationId, + String notes, + ZonedDateTime timestamp, + Principal principal) { + // TODO check if user can modify transaction once we have a centralized service. + var existingTransaction = transactionRepository.loadByReservationId(reservationId); + Validate.isTrue(existingTransaction.isTimestampEditable() || timestamp == null, "Cannot modify timestamp"); + var existingMetadata = new HashMap<>(existingTransaction.getMetadata()); + existingMetadata.put(Transaction.NOTES_KEY, notes); + int result = transactionRepository.updateDetailsById(existingTransaction.getId(), existingMetadata, requireNonNullElse(timestamp, existingTransaction.getTimestamp())); + Validate.isTrue(result == 1, "Expected 1, got " + result); + } + private boolean feesUpdated(Transaction transaction, PaymentInformation paymentInformation) { return transaction.getPlatformFee() != safeParseLong(paymentInformation.getPlatformFee()) || transaction.getGatewayFee() != safeParseLong(paymentInformation.getFee()); @@ -234,14 +270,11 @@ public Optional getTransactionStatus(TicketReservation reservatio return transactionRepository.loadOptionalByReservationId(reservation.getId()) .filter(transaction -> transaction.getPaymentProxy().getPaymentMethod() == paymentMethod) .map(transaction -> { - switch(transaction.getStatus()) { - case COMPLETE: - return PaymentResult.successful(transaction.getPaymentId()); - case FAILED: - return PaymentResult.failed(null); - default: - return PaymentResult.initialized(transaction.getPaymentId()); - } + return switch (transaction.getStatus()) { + case COMPLETE -> PaymentResult.successful(transaction.getPaymentId()); + case FAILED -> PaymentResult.failed(null); + default -> PaymentResult.initialized(transaction.getPaymentId()); + }; }); } @@ -269,13 +302,19 @@ public boolean removePaymentTokenReservation(String reservationId) { }).orElse(false); } - @Data + public static final class PaymentMethodDTO { public enum PaymentMethodStatus { ACTIVE, ERROR } + public PaymentMethodDTO(PaymentProxy paymentProxy, PaymentMethod paymentMethod, PaymentMethodStatus status) { + this.paymentProxy = paymentProxy; + this.paymentMethod = paymentMethod; + this.status = status; + } + private final PaymentProxy paymentProxy; private final PaymentMethod paymentMethod; @@ -285,7 +324,7 @@ public boolean isActive() { return status == PaymentMethodStatus.ACTIVE; } - @Deprecated + @Deprecated(forRemoval = true) public Set getOnlyForCurrency() { return paymentProxy.getOnlyForCurrency(); } @@ -293,5 +332,13 @@ public Set getOnlyForCurrency() { public PaymentMethod getPaymentMethod() { return paymentMethod; } + + public PaymentProxy getPaymentProxy() { + return paymentProxy; + } + + public PaymentMethodStatus getStatus() { + return status; + } } } diff --git a/src/main/java/alfio/manager/PollManager.java b/src/main/java/alfio/manager/PollManager.java index 3597fe393e..4956832f3b 100644 --- a/src/main/java/alfio/manager/PollManager.java +++ b/src/main/java/alfio/manager/PollManager.java @@ -26,7 +26,6 @@ import alfio.repository.*; import alfio.util.Json; import alfio.util.PinGenerator; -import lombok.AllArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; @@ -43,7 +42,6 @@ import static java.util.Objects.requireNonNullElse; @Component -@AllArgsConstructor @Transactional public class PollManager { private final PollRepository pollRepository; @@ -53,6 +51,20 @@ public class PollManager { private final TicketSearchRepository ticketSearchRepository; private final AuditingRepository auditingRepository; + public PollManager(PollRepository pollRepository, + EventRepository eventRepository, + TicketRepository ticketRepository, + NamedParameterJdbcTemplate jdbcTemplate, + TicketSearchRepository ticketSearchRepository, + AuditingRepository auditingRepository) { + this.pollRepository = pollRepository; + this.eventRepository = eventRepository; + this.ticketRepository = ticketRepository; + this.jdbcTemplate = jdbcTemplate; + this.ticketSearchRepository = ticketSearchRepository; + this.auditingRepository = auditingRepository; + } + public Result> getActiveForEvent(String eventName, String pin) { return validatePinAndEvent(pin, eventName) .flatMap(eventAndTicket -> Result.success(pollRepository.findActiveForEvent(eventAndTicket.getLeft().getId()))); @@ -139,9 +151,9 @@ public Optional updatePoll(String eventName, PollModification f .flatMap(event -> { var pollId = form.getId(); var existingPollWithOptions = getSingleForEvent(pollId, event).orElseThrow(); - var existingPoll = existingPollWithOptions.getPoll(); - var tags = existingPoll.getAllowedTags(); - if(form.isAccessRestricted() == existingPoll.getAllowedTags().isEmpty()) { + var existingPoll = existingPollWithOptions.poll(); + var tags = existingPoll.allowedTags(); + if(form.isAccessRestricted() == existingPoll.allowedTags().isEmpty()) { tags = form.isAccessRestricted() ? List.of(UUID.randomUUID().toString()) : List.of(); } Validate.isTrue(pollRepository.update(form.getTitle(), form.getDescription(), tags, form.getOrder(), pollId, event.getId()) == 1); @@ -174,7 +186,7 @@ public Optional> searchTicketsToAllow(String eventName, Lo Validate.isTrue(StringUtils.isNotBlank(filter)); return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) .flatMap(event -> pollRepository.findSingleForEvent(event.getId(), pollId) - .map(p -> ticketSearchRepository.filterConfirmedTicketsInEventForPoll(event.getId(), 20, "%"+filter+"%", p.getAllowedTags()))); + .map(p -> ticketSearchRepository.filterConfirmedTicketsInEventForPoll(event.getId(), 20, "%"+filter+"%", p.allowedTags()))); } public Optional allowTicketsToVote(String eventName, List ids, long pollId) { @@ -182,8 +194,8 @@ public Optional allowTicketsToVote(String eventName, List ids, return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) .map(event -> { var poll = pollRepository.findSingleForEvent(event.getId(), pollId).orElseThrow(); - Validate.isTrue(CollectionUtils.isNotEmpty(poll.getAllowedTags())); - var tag = poll.getAllowedTags().get(0); + Validate.isTrue(CollectionUtils.isNotEmpty(poll.allowedTags())); + var tag = poll.allowedTags().get(0); var result = ticketRepository.tagTickets(ids, event.getId(), tag); Validate.isTrue(ids.size() == result, "Unable to tag tickets"); var auditingResults = auditingRepository.registerTicketTag(ids, List.of(Map.of("tag", tag))); @@ -196,13 +208,13 @@ public Optional> removeParticipants(String eventName, List return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) .map(event -> { var poll = pollRepository.findSingleForEvent(event.getId(), pollId).orElseThrow(); - Validate.isTrue(CollectionUtils.isNotEmpty(poll.getAllowedTags())); - var tag = poll.getAllowedTags().get(0); + Validate.isTrue(CollectionUtils.isNotEmpty(poll.allowedTags())); + var tag = poll.allowedTags().get(0); var result = ticketRepository.untagTickets(ticketIds, event.getId(), tag); Validate.isTrue(result == 1, "Error while removing tag"); var auditingResults = auditingRepository.registerTicketUntag(ticketIds, List.of(Map.of("tag", tag))); Validate.isTrue(auditingResults == ticketIds.size(), "Error while writing auditing"); - return ticketRepository.getTicketsForEventByTags(event.getId(), poll.getAllowedTags()); + return ticketRepository.getTicketsForEventByTags(event.getId(), poll.allowedTags()); }); } @@ -211,7 +223,7 @@ public Optional removeOption(String eventName, Long pollId, Lon .flatMap(event -> { var poll = pollRepository.findSingleForEvent(event.getId(), pollId).orElseThrow(); Validate.isTrue(pollRepository.deleteOption(pollId, optionId) == 1, "Error while deleting option"); - return getSingleForEvent(poll.getId(), event); + return getSingleForEvent(poll.id(), event); }); } @@ -219,7 +231,7 @@ public Optional> fetchAllowedTickets(String eventName, lon return eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName) .map(event -> { var poll = pollRepository.findSingleForEvent(event.getId(), pollId).orElseThrow(); - return ticketRepository.getTicketsForEventByTags(event.getId(), poll.getAllowedTags()); + return ticketRepository.getTicketsForEventByTags(event.getId(), poll.allowedTags()); }); } @@ -228,13 +240,13 @@ public Optional getStatisticsFor(String eventName, long pollId) .flatMap(event -> pollRepository.findSingleForEvent(event.getId(), pollId) .map(p -> { int allowedParticipants; - if(p.getAllowedTags().isEmpty()) { + if(p.allowedTags().isEmpty()) { allowedParticipants = eventRepository.findStatisticsFor(event.getId()).getCheckedInTickets(); } else { - allowedParticipants = ticketRepository.countTicketsMatchingTagsAndStatus(event.getId(), p.getAllowedTags(), List.of(Ticket.TicketStatus.CHECKED_IN.name())); + allowedParticipants = ticketRepository.countTicketsMatchingTagsAndStatus(event.getId(), p.allowedTags(), List.of(Ticket.TicketStatus.CHECKED_IN.name())); } - var statistics = pollRepository.getStatisticsFor(p.getId(), event.getId()); - return new PollStatistics(statistics.stream().mapToInt(PollOptionStatistics::getVotes).sum(), allowedParticipants, statistics); + var statistics = pollRepository.getStatisticsFor(p.id(), event.getId()); + return new PollStatistics(statistics.stream().mapToInt(PollOptionStatistics::votes).sum(), allowedParticipants, statistics); })); } diff --git a/src/main/java/alfio/manager/PromoCodeRequestManager.java b/src/main/java/alfio/manager/PromoCodeRequestManager.java index 3253f8f744..1598f128c7 100644 --- a/src/main/java/alfio/manager/PromoCodeRequestManager.java +++ b/src/main/java/alfio/manager/PromoCodeRequestManager.java @@ -20,6 +20,7 @@ import alfio.manager.support.response.ValidatedResponse; import alfio.model.Event; import alfio.model.PromoCodeDiscount; +import alfio.model.PromoCodeUsageResult; import alfio.model.SpecialPrice; import alfio.model.modification.TicketReservationModification; import alfio.model.result.ValidationResult; @@ -31,7 +32,6 @@ import alfio.util.ErrorsCode; import alfio.util.RequestUtils; import alfio.util.ReservationUtil; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; @@ -44,6 +44,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.function.BiConsumer; @@ -52,7 +53,6 @@ import static alfio.model.PromoCodeDiscount.categoriesOrNull; @Component -@AllArgsConstructor public class PromoCodeRequestManager { private final SpecialPriceRepository specialPriceRepository; @@ -63,6 +63,22 @@ public class PromoCodeRequestManager { private final TicketReservationManager ticketReservationManager; private final ClockProvider clockProvider; + public PromoCodeRequestManager(SpecialPriceRepository specialPriceRepository, + PromoCodeDiscountRepository promoCodeRepository, + TicketCategoryRepository ticketCategoryRepository, + EventManager eventManager, + EventRepository eventRepository, + TicketReservationManager ticketReservationManager, + ClockProvider clockProvider) { + this.specialPriceRepository = specialPriceRepository; + this.promoCodeRepository = promoCodeRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.eventManager = eventManager; + this.eventRepository = eventRepository; + this.ticketReservationManager = ticketReservationManager; + this.clockProvider = clockProvider; + } + enum PromoCodeType { SPECIAL_PRICE, PROMO_CODE_DISCOUNT, TICKET_CATEGORY_CODE, NOT_FOUND } @@ -136,7 +152,7 @@ public ValidatedResponse, Optional maybeSpecialCode = Optional.ofNullable(StringUtils.trimToNull(promoCode)); Optional specialCode = maybeSpecialCode.flatMap(specialPriceRepository::getByCode); - Optional promotionCodeDiscount = maybeSpecialCode.flatMap((trimmedCode) -> promoCodeRepository.findPublicPromoCodeInEventOrOrganization(event.getId(), trimmedCode)); + Optional promotionCodeDiscount = maybeSpecialCode.flatMap(trimmedCode -> promoCodeRepository.findPublicPromoCodeInEventOrOrganization(event.getId(), trimmedCode)); var result = Pair.of(specialCode, promotionCodeDiscount); @@ -152,15 +168,16 @@ public ValidatedResponse, Optional(ValidationResult.success(), result); } @@ -211,4 +228,26 @@ private Optional createTicketReservation(ReservationForm reservation, .flatMap(selected -> ticketReservationManager.createTicketReservation(event, selected.getLeft(), selected.getRight(), promoCodeDiscount, locale, bindingResult, principal)); } + public Optional findById(int id) { + return promoCodeRepository.findOptionalById(id); + } + + public void disablePromoCode(int promoCodeId) { + promoCodeRepository.updateEventPromoCodeEnd(promoCodeId, ZonedDateTime.now(clockProvider.getClock())); + } + + public int countUsage(int promoCodeId) { + Optional code = findById(promoCodeId); + if(code.isEmpty()) { + return 0; + } + return promoCodeRepository.countConfirmedPromoCode(promoCodeId, categoriesOrNull(code.get()), null, categoriesOrNull(code.get()) != null ? "X" : null); + } + + public List retrieveDetailedUsage(int promoCodeId, Integer eventId) { + return findById(promoCodeId) + .map(pc -> promoCodeRepository.findDetailedUsage(pc.getPromoCode(), eventId)) + .orElse(List.of()); + } + } diff --git a/src/main/java/alfio/manager/PurchaseContextManager.java b/src/main/java/alfio/manager/PurchaseContextManager.java index e57f16639c..0a4d8112de 100644 --- a/src/main/java/alfio/manager/PurchaseContextManager.java +++ b/src/main/java/alfio/manager/PurchaseContextManager.java @@ -22,46 +22,60 @@ import alfio.repository.EventRepository; import alfio.repository.SubscriptionRepository; import alfio.repository.TicketReservationRepository; -import lombok.extern.log4j.Log4j2; +import alfio.repository.user.OrganizationRepository; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import java.security.Principal; +import java.util.Objects; import java.util.Optional; import java.util.UUID; @Transactional(readOnly = true) @Component -@Log4j2 public class PurchaseContextManager { + private static final Logger log = LoggerFactory.getLogger(PurchaseContextManager.class); + private final EventRepository eventRepository; private final SubscriptionRepository subscriptionRepository; private final TicketReservationRepository ticketReservationRepository; + private final OrganizationRepository organizationRepository; public PurchaseContextManager(EventRepository eventRepository, SubscriptionRepository subscriptionRepository, - TicketReservationRepository ticketReservationRepository) { + TicketReservationRepository ticketReservationRepository, + OrganizationRepository organizationRepository) { this.eventRepository = eventRepository; this.subscriptionRepository = subscriptionRepository; this.ticketReservationRepository = ticketReservationRepository; + this.organizationRepository = organizationRepository; } public Optional findBy(PurchaseContext.PurchaseContextType purchaseContextType, String publicIdentifier) { - switch (purchaseContextType) { - case event: return eventRepository.findOptionalByShortName(publicIdentifier); - case subscription: return subscriptionRepository.findOne(UUID.fromString(publicIdentifier)); - default: throw new IllegalStateException("not a covered type " + purchaseContextType); - } + return switch (purchaseContextType) { + case event -> eventRepository.findOptionalByShortName(publicIdentifier); + case subscription -> subscriptionRepository.findOne(UUID.fromString(publicIdentifier)); + default -> throw new IllegalStateException("not a covered type " + purchaseContextType); + }; + } + + // temporary until we have a proper ownership check service (WIP) + public boolean validateAccess(PurchaseContext purchaseContext, Principal principal) { + var username = Objects.requireNonNull(principal).getName(); + return organizationRepository.findOrganizationForUser(username, purchaseContext.getOrganizationId()).isPresent(); } Optional findById(PurchaseContext.PurchaseContextType purchaseContextType, String idAsString) { - switch (purchaseContextType) { - case event: return eventRepository.findOptionalById(Integer.parseInt(idAsString)); - case subscription: return subscriptionRepository.findOne(UUID.fromString(idAsString)); - default: throw new IllegalStateException("not a covered type " + purchaseContextType); - } + return switch (purchaseContextType) { + case event -> eventRepository.findOptionalById(Integer.parseInt(idAsString)); + case subscription -> subscriptionRepository.findOne(UUID.fromString(idAsString)); + default -> throw new IllegalStateException("not a covered type " + purchaseContextType); + }; } public Optional findByReservationId(String reservationId) { diff --git a/src/main/java/alfio/manager/PurchaseContextSearchManager.java b/src/main/java/alfio/manager/PurchaseContextSearchManager.java index 52432d6e69..f8ca3285a2 100644 --- a/src/main/java/alfio/manager/PurchaseContextSearchManager.java +++ b/src/main/java/alfio/manager/PurchaseContextSearchManager.java @@ -18,41 +18,80 @@ import alfio.model.Event; import alfio.model.PurchaseContext; +import alfio.model.ReservationPaymentDetail; import alfio.model.TicketReservation; import alfio.model.subscription.SubscriptionDescriptor; +import alfio.model.transaction.PaymentProxy; import alfio.repository.TicketSearchRepository; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; +import java.util.stream.Collectors; import static java.util.stream.Collectors.toList; @Component @Transactional(readOnly = true) -@AllArgsConstructor public class PurchaseContextSearchManager { + private static final int PAGE_SIZE = 50; + private static final List SUPPORTED_PAYMENT_METHODS = EnumSet.complementOf(EnumSet.of(PaymentProxy.NONE, PaymentProxy.ADMIN)) + .stream() + .map(PaymentProxy::name) + .collect(Collectors.toUnmodifiableList()); private final TicketSearchRepository ticketSearchRepository; + public PurchaseContextSearchManager(TicketSearchRepository ticketSearchRepository) { + this.ticketSearchRepository = ticketSearchRepository; + } + public Pair, Integer> findAllReservationsFor(PurchaseContext purchaseContext, Integer page, String search, List status) { - final int pageSize = 50; - int offset = page == null ? 0 : page * pageSize; + int offset = page == null ? 0 : page * PAGE_SIZE; String toSearch = StringUtils.trimToNull(search); toSearch = toSearch == null ? null : ("%" + toSearch + "%"); List toFilter = (status == null || status.isEmpty() ? Arrays.asList(TicketReservation.TicketReservationStatus.values()) : status).stream().map(TicketReservation.TicketReservationStatus::toString).collect(toList()); if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { var event = (Event)purchaseContext; - List reservationsForEvent = ticketSearchRepository.findReservationsForEvent(event.getId(), offset, pageSize, toSearch, toFilter); + List reservationsForEvent = ticketSearchRepository.findReservationsForEvent(event.getId(), offset, PAGE_SIZE, toSearch, toFilter); return Pair.of(reservationsForEvent, ticketSearchRepository.countReservationsForEvent(event.getId(), toSearch, toFilter)); } else { var subscription = (SubscriptionDescriptor) purchaseContext; - List reservationsForSubscription = ticketSearchRepository.findReservationsForSubscription(subscription.getId(), offset, pageSize, toSearch, toFilter); + List reservationsForSubscription = ticketSearchRepository.findReservationsForSubscription(subscription.getId(), offset, PAGE_SIZE, toSearch, toFilter); return Pair.of(reservationsForSubscription, ticketSearchRepository.countReservationsForSubscription(subscription.getId(), toSearch, toFilter)); } } + + public Pair, Integer> findAllPaymentsFor(PurchaseContext purchaseContext, Integer page, String search) { + int offset = page == null ? 0 : page * PAGE_SIZE; + String toSearch = StringUtils.trimToNull(search); + toSearch = toSearch == null ? null : ("%" + toSearch + "%"); + var toFilter = List.of(TicketReservation.TicketReservationStatus.COMPLETE.name()); + + if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + var event = (Event)purchaseContext; + List reservationsForEvent = ticketSearchRepository.findAllPaymentsForEvent(event.getId(), offset, PAGE_SIZE, toSearch, toFilter, SUPPORTED_PAYMENT_METHODS); + return Pair.of(reservationsForEvent, ticketSearchRepository.countConfirmedPaymentsForEvent(event.getId(), toSearch, toFilter, SUPPORTED_PAYMENT_METHODS)); + } else { + // functionality is not yet available for subscriptions + throw new UnsupportedOperationException("not implemented"); + } + } + + public List findAllPaymentsForExport(PurchaseContext purchaseContext, String search) { + String toSearch = StringUtils.trimToNull(search); + toSearch = toSearch == null ? null : ("%" + toSearch + "%"); + var toFilter = List.of(TicketReservation.TicketReservationStatus.COMPLETE.name()); + if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + var event = (Event)purchaseContext; + return ticketSearchRepository.findAllEventPaymentsForExport(event.getId(), toSearch, toFilter, SUPPORTED_PAYMENT_METHODS); + } else { + // functionality is not yet available for subscriptions + throw new UnsupportedOperationException("not implemented"); + } + } } diff --git a/src/main/java/alfio/manager/RecaptchaService.java b/src/main/java/alfio/manager/RecaptchaService.java index 267a80f45a..3b00389749 100644 --- a/src/main/java/alfio/manager/RecaptchaService.java +++ b/src/main/java/alfio/manager/RecaptchaService.java @@ -20,8 +20,6 @@ import alfio.model.system.ConfigurationKeys; import alfio.util.HttpUtils; import alfio.util.Json; -import lombok.AllArgsConstructor; -import lombok.Data; import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Component; @@ -32,12 +30,16 @@ import java.util.Map; @Component -@AllArgsConstructor public class RecaptchaService { private final HttpClient client; private final ConfigurationManager configurationManager; + public RecaptchaService(HttpClient client, ConfigurationManager configurationManager) { + this.client = client; + this.configurationManager = configurationManager; + } + public boolean checkRecaptcha(String recaptchaResponse, HttpServletRequest req) { return configurationManager.getForSystem(ConfigurationKeys.RECAPTCHA_SECRET).getValue() @@ -63,8 +65,15 @@ private static boolean recaptchaRequest(HttpClient client, String secret, String } } - @Data public static class RecatpchaResponse { private boolean success; + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } } } diff --git a/src/main/java/alfio/manager/ReservationFinalizer.java b/src/main/java/alfio/manager/ReservationFinalizer.java new file mode 100644 index 0000000000..ae80e85d95 --- /dev/null +++ b/src/main/java/alfio/manager/ReservationFinalizer.java @@ -0,0 +1,488 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager; + +import alfio.manager.payment.PaymentSpecification; +import alfio.manager.support.FeeCalculator; +import alfio.manager.support.IncompatibleStateException; +import alfio.manager.support.RetryFinalizeReservation; +import alfio.manager.support.reservation.OrderSummaryGenerator; +import alfio.manager.support.reservation.ReservationAuditingHelper; +import alfio.manager.support.reservation.ReservationCostCalculator; +import alfio.manager.support.reservation.ReservationEmailContentHelper; +import alfio.manager.system.AdminJobManager; +import alfio.manager.system.ConfigurationLevel; +import alfio.manager.system.ConfigurationManager; +import alfio.model.*; +import alfio.model.metadata.TicketMetadata; +import alfio.model.metadata.TicketMetadataContainer; +import alfio.model.modification.TransactionMetadataModification; +import alfio.model.subscription.SubscriptionDescriptor; +import alfio.model.support.UserIdAndOrganizationId; +import alfio.model.system.command.FinalizeReservation; +import alfio.model.transaction.PaymentProxy; +import alfio.model.transaction.Transaction; +import alfio.repository.*; +import alfio.repository.system.AdminJobQueueRepository; +import alfio.repository.user.UserRepository; +import alfio.util.ClockProvider; +import alfio.util.Json; +import alfio.util.LocaleUtil; +import alfio.util.ReservationUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; + +import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; +import java.util.*; +import java.util.function.Function; + +import static alfio.manager.system.AdminJobExecutor.JobName.RETRY_RESERVATION_CONFIRMATION; +import static alfio.model.Audit.EventType.SUBSCRIPTION_ACQUIRED; +import static alfio.model.TicketReservation.TicketReservationStatus.*; +import static alfio.model.system.ConfigurationKeys.*; +import static alfio.util.ReservationUtil.hasPrivacyPolicy; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static java.util.Objects.requireNonNullElse; +import static java.util.stream.Collectors.toMap; + +@Component +public class ReservationFinalizer { + private static final Logger log = LoggerFactory.getLogger(ReservationFinalizer.class); + private final TransactionTemplate transactionTemplate; + private final TicketReservationRepository ticketReservationRepository; + private final UserRepository userRepository; + private final ExtensionManager extensionManager; + private final AuditingRepository auditingRepository; + private final ClockProvider clockProvider; + private final ConfigurationManager configurationManager; + private final SubscriptionRepository subscriptionRepository; + private final ReservationAuditingHelper auditingHelper; + private final TicketRepository ticketRepository; + private final ReservationEmailContentHelper reservationOperationHelper; + private final SpecialPriceRepository specialPriceRepository; + private final WaitingQueueManager waitingQueueManager; + private final TicketCategoryRepository ticketCategoryRepository; + private final ReservationCostCalculator reservationCostCalculator; + private final BillingDocumentManager billingDocumentManager; + private final AdditionalServiceItemRepository additionalServiceItemRepository; + private final OrderSummaryGenerator orderSummaryGenerator; + private final ReservationEmailContentHelper reservationHelper; + private final TransactionRepository transactionRepository; + private final AdminJobQueueRepository adminJobQueueRepository; + private final PurchaseContextManager purchaseContextManager; + private final Json json; + + + public ReservationFinalizer(PlatformTransactionManager transactionManager, + TicketReservationRepository ticketReservationRepository, + UserRepository userRepository, + ExtensionManager extensionManager, + AuditingRepository auditingRepository, + ClockProvider clockProvider, + ConfigurationManager configurationManager, + SubscriptionRepository subscriptionRepository, + TicketRepository ticketRepository, + ReservationEmailContentHelper reservationEmailContentHelper, + SpecialPriceRepository specialPriceRepository, + WaitingQueueManager waitingQueueManager, + TicketCategoryRepository ticketCategoryRepository, + ReservationCostCalculator reservationCostCalculator, + BillingDocumentManager billingDocumentManager, + AdditionalServiceItemRepository additionalServiceItemRepository, + OrderSummaryGenerator orderSummaryGenerator, + TransactionRepository transactionRepository, + AdminJobQueueRepository adminJobQueueRepository, + PurchaseContextManager purchaseContextManager, + Json json) { + this.ticketReservationRepository = ticketReservationRepository; + this.userRepository = userRepository; + this.extensionManager = extensionManager; + this.auditingRepository = auditingRepository; + this.clockProvider = clockProvider; + this.configurationManager = configurationManager; + this.subscriptionRepository = subscriptionRepository; + this.ticketRepository = ticketRepository; + this.reservationOperationHelper = reservationEmailContentHelper; + this.specialPriceRepository = specialPriceRepository; + this.waitingQueueManager = waitingQueueManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.reservationCostCalculator = reservationCostCalculator; + this.billingDocumentManager = billingDocumentManager; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.transactionRepository = transactionRepository; + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + this.transactionTemplate = new TransactionTemplate(transactionManager, definition); + this.orderSummaryGenerator = orderSummaryGenerator; + this.reservationHelper = reservationEmailContentHelper; + this.auditingHelper = new ReservationAuditingHelper(auditingRepository); + this.adminJobQueueRepository = adminJobQueueRepository; + this.purchaseContextManager = purchaseContextManager; + this.json = json; + } + + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void finalizeCommandReceived(FinalizeReservation finalizeReservation) { + transactionTemplate.executeWithoutResult(ctx -> processFinalizeReservation(finalizeReservation, ctx, true)); + } + + public void retryFinalizeReservation(RetryFinalizeReservation retryFinalizeReservation) { + var purchaseContextAndReservation = purchaseContextManager.getReservationWithPurchaseContext(retryFinalizeReservation.getReservationId()).orElseThrow(); + var reservation = purchaseContextAndReservation.getRight(); + var purchaseContext = purchaseContextAndReservation.getLeft(); + var costResult = reservationCostCalculator.totalReservationCostWithVAT(reservation); + var totalPrice = costResult.getLeft(); + var orderSummary = orderSummaryGenerator.orderSummaryForReservation(reservation, purchaseContext); + var paymentSpecification = new PaymentSpecification(reservation, totalPrice, purchaseContext, null, orderSummary, retryFinalizeReservation.isTcAccepted(), retryFinalizeReservation.isPrivacyPolicyAccepted()); + transactionTemplate.executeWithoutResult(ctx -> processFinalizeReservation(new FinalizeReservation(paymentSpecification, retryFinalizeReservation.getPaymentProxy(), retryFinalizeReservation.isSendReservationConfirmationEmail(), retryFinalizeReservation.isSendTickets(), retryFinalizeReservation.getUsername(), retryFinalizeReservation.getOriginalStatus()), ctx, false)); + } + + private void processFinalizeReservation(FinalizeReservation finalizeReservation, TransactionStatus ctx, boolean scheduleRetryOnError) { + Object savepoint = ctx.createSavepoint(); + var spec = finalizeReservation.getPaymentSpecification(); + try { + var reservation = ticketReservationRepository.findReservationById(spec.getReservationId()); + var totalPrice = reservationCostCalculator.totalReservationCostWithVAT(reservation); + var metadata = ticketReservationRepository.getMetadata(reservation.getId()); + // generate invoice number + if (reservation.getStatus() != COMPLETE && StringUtils.isBlank(reservation.getInvoiceNumber()) && !metadata.isReadyForConfirmation()) { + boolean traceEnabled = log.isTraceEnabled(); + if (traceEnabled) { + log.trace("Generating invoice number for reservation {}", reservation.getId()); + } + var invoiceNumberOptional = billingDocumentManager.generateInvoiceNumber(spec, totalPrice.getKey()); + invoiceNumberOptional.ifPresent(s -> setInvoiceNumber(spec.getReservationId(), s)); + } + // no exceptions here. We can save the progress + ticketReservationRepository.setMetadata(reservation.getId(), metadata.withReadyForConfirmation(true)); + ctx.releaseSavepoint(savepoint); + savepoint = ctx.createSavepoint(); + + // complete reservation + completeReservation(finalizeReservation); + } catch(Exception e) { + ctx.rollbackToSavepoint(savepoint); + if (!scheduleRetryOnError) { + throw e; + } + boolean scheduled = AdminJobManager.executionScheduler( + RETRY_RESERVATION_CONFIRMATION, + Map.of("payload", json.asJsonString(RetryFinalizeReservation.fromFinalizeReservation(finalizeReservation))), + ZonedDateTime.now(clockProvider.getClock()).plusSeconds(2L) + ).apply(adminJobQueueRepository); + if(!scheduled) { + log.warn("Cannot schedule retry for reservation {}", spec.getReservationId()); + // throw exception only if we can't schedule the retry + throw e; + } else { + log.warn("Error while confirming reservation "+ spec.getReservationId() + ". Will retry in 2s", e); + } + } finally { + ctx.releaseSavepoint(savepoint); + } + } + + + private void setInvoiceNumber(String reservationId, String invoiceNumber) { + if (log.isTraceEnabled()) { + log.trace("Set invoice number {} for reservation {}", invoiceNumber, reservationId); + } + ticketReservationRepository.setInvoiceNumber(reservationId, invoiceNumber); + } + + private void completeReservation(FinalizeReservation finalizeReservation) { + var spec = finalizeReservation.getPaymentSpecification(); + var paymentProxy = finalizeReservation.getPaymentProxy(); + var username = finalizeReservation.getUsername(); + var reservationId = spec.getReservationId(); + var purchaseContext = spec.getPurchaseContext(); + final TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId); + if (reservation.getStatus() != FINALIZING && reservation.getStatus() != OFFLINE_FINALIZING) { + throw new IncompatibleStateException("Status " + reservation.getStatus() + " is not compatible with finalization."); + } + var metadata = ticketReservationRepository.getMetadata(reservationId); + if (!metadata.isReadyForConfirmation()) { + throw new IncompatibleStateException("Reservation is not ready to be confirmed"); + } + // retrieve reservation owner if username is null + Integer userId; + if(username != null) { + userId = userRepository.getByUsername(username).getId(); + } else { + userId = ticketReservationRepository.getReservationOwnerAndOrganizationId(reservationId) + .map(UserIdAndOrganizationId::getUserId) + .orElse(null); + } + ticketReservationRepository.setMetadata(reservationId, metadata.withFinalized(true)); + Locale locale = LocaleUtil.forLanguageTag(reservation.getUserLanguage()); + List tickets = null; + if(paymentProxy != PaymentProxy.OFFLINE) { + ticketReservationRepository.updateReservationStatus(reservationId, COMPLETE.name()); + tickets = acquireItems(paymentProxy, reservationId, spec.getEmail(), spec.getCustomerName(), spec.getLocale().getLanguage(), spec.getBillingAddress(), spec.getCustomerReference(), spec.getPurchaseContext(), finalizeReservation.isSendTickets()); + extensionManager.handleReservationConfirmation(reservation, ticketReservationRepository.getBillingDetailsForReservation(reservationId), spec.getPurchaseContext()); + } else { + // if paymentProxy is offline, we set the appropriate status to wait for payment + ticketReservationRepository.updateReservationStatus(reservationId, finalizeReservation.getOriginalStatus().name()); + } + + Date eventTime = new Date(); + auditingRepository.insert(reservationId, userId, purchaseContext, Audit.EventType.RESERVATION_COMPLETE, eventTime, Audit.EntityType.RESERVATION, reservationId); + ticketReservationRepository.updateRegistrationTimestamp(reservationId, ZonedDateTime.now(clockProvider.withZone(spec.getPurchaseContext().getZoneId()))); + if(spec.isTcAccepted()) { + auditingRepository.insert(reservationId, userId, purchaseContext, Audit.EventType.TERMS_CONDITION_ACCEPTED, eventTime, Audit.EntityType.RESERVATION, reservationId, singletonList(singletonMap("termsAndConditionsUrl", spec.getPurchaseContext().getTermsAndConditionsUrl()))); + } + + if(hasPrivacyPolicy(spec.getPurchaseContext()) && spec.isPrivacyAccepted()) { + auditingRepository.insert(reservationId, userId, purchaseContext, Audit.EventType.PRIVACY_POLICY_ACCEPTED, eventTime, Audit.EntityType.RESERVATION, reservationId, singletonList(singletonMap("privacyPolicyUrl", spec.getPurchaseContext().getPrivacyPolicyUrl()))); + } + + if(finalizeReservation.isSendReservationConfirmationEmail()) { + TicketReservation updatedReservation = ticketReservationRepository.findReservationById(reservationId); + sendConfirmationEmailIfNecessary(updatedReservation, tickets, purchaseContext, locale, username); + reservationOperationHelper.sendReservationCompleteEmailToOrganizer(spec.getPurchaseContext(), updatedReservation, locale, username); + } + } + + public void sendConfirmationEmailIfNecessary(TicketReservation ticketReservation, + List tickets, + PurchaseContext purchaseContext, + Locale locale, + String username) { + if (!ticketReservationRepository.getMetadata(ticketReservation.getId()).isFinalized()) { + throw new IncompatibleStateException("Reservation confirmed but not yet finalized"); + } + if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + var config = configurationManager.getFor(List.of(SEND_RESERVATION_EMAIL_IF_NECESSARY, SEND_TICKETS_AUTOMATICALLY), purchaseContext.getConfigurationLevel()); + if(ticketReservation.getSrcPriceCts() > 0 + || CollectionUtils.isEmpty(tickets) || tickets.size() > 1 + || !tickets.get(0).getEmail().equals(ticketReservation.getEmail()) + || !config.get(SEND_RESERVATION_EMAIL_IF_NECESSARY).getValueAsBooleanOrDefault() + || !config.get(SEND_TICKETS_AUTOMATICALLY).getValueAsBooleanOrDefault() + ) { + reservationOperationHelper.sendConfirmationEmail(purchaseContext, ticketReservation, locale, username); + } + } else { + reservationOperationHelper.sendConfirmationEmail(purchaseContext, ticketReservation, locale, username); + } + } + + public void acquireSpecialPriceTokens(String reservationId) { + specialPriceRepository.updateStatusForReservation(singletonList(reservationId), SpecialPrice.Status.TAKEN.toString()); + } + + private List acquireItems(PaymentProxy paymentProxy, String reservationId, String email, CustomerName customerName, + String userLanguage, String billingAddress, String customerReference, PurchaseContext purchaseContext, boolean sendTickets) { + switch (purchaseContext.getType()) { + case event -> acquireEventTickets(paymentProxy, reservationId, purchaseContext, purchaseContext.event().orElseThrow()); + case subscription -> acquireSubscription(paymentProxy, reservationId, purchaseContext, customerName, email); + default -> throw new IllegalStateException("not supported purchase context"); + } + + acquireSpecialPriceTokens(reservationId); + ZonedDateTime timestamp = ZonedDateTime.now(clockProvider.getClock()); + int updatedReservation = ticketReservationRepository.updateTicketReservation(reservationId, COMPLETE.toString(), email, + customerName.getFullName(), customerName.getFirstName(), customerName.getLastName(), userLanguage, billingAddress, timestamp, paymentProxy.toString(), customerReference); + + Validate.isTrue(updatedReservation == 1, "expected exactly one updated reservation, got " + updatedReservation); + + waitingQueueManager.fireReservationConfirmed(reservationId); + //we must notify the plugins about ticket assignment and send them by email + TicketReservation reservation = findById(reservationId).orElseThrow(IllegalStateException::new); + List assignedTickets = findTicketsInReservation(reservationId); + assignedTickets.stream() + .filter(ticket -> StringUtils.isNotBlank(ticket.getFullName()) || StringUtils.isNotBlank(ticket.getFirstName()) || StringUtils.isNotBlank(ticket.getEmail())) + .forEach(ticket -> { + var event = purchaseContext.event().orElseThrow(); + Locale locale = LocaleUtil.forLanguageTag(ticket.getUserLanguage()); + var additionalInfo = reservationOperationHelper.retrieveAttendeeAdditionalInfoForTicket(ticket); + if((paymentProxy != PaymentProxy.ADMIN || sendTickets) && configurationManager.getFor(SEND_TICKETS_AUTOMATICALLY, ConfigurationLevel.event(event)).getValueAsBooleanOrDefault()) { + reservationOperationHelper.sendTicketByEmail(ticket, locale, event, reservationHelper.getTicketEmailGenerator(event, reservation, locale, additionalInfo)); + } + extensionManager.handleTicketAssignment(ticket, ticketCategoryRepository.getById(ticket.getCategoryId()), additionalInfo); + }); + return assignedTickets; + } + + private void acquireSubscription(PaymentProxy paymentProxy, String reservationId, PurchaseContext purchaseContext, CustomerName customerName, String email) { + var status = paymentProxy.isDeskPaymentRequired() ? AllocationStatus.TO_BE_PAID : AllocationStatus.ACQUIRED; + var subscriptionDescriptor = (SubscriptionDescriptor) purchaseContext; + ZonedDateTime validityFrom = null; + ZonedDateTime validityTo = null; + var confirmationTimestamp = subscriptionDescriptor.now(clockProvider); + if(subscriptionDescriptor.getValidityFrom() != null) { + validityFrom = subscriptionDescriptor.getValidityFrom(); + validityTo = subscriptionDescriptor.getValidityTo(); + } else if(subscriptionDescriptor.getValidityUnits() != null) { + validityFrom = confirmationTimestamp; + var temporalUnit = requireNonNullElse(subscriptionDescriptor.getValidityTimeUnit(), SubscriptionDescriptor.SubscriptionTimeUnit.DAYS).getTemporalUnit(); + validityTo = confirmationTimestamp.plus(subscriptionDescriptor.getValidityUnits(), temporalUnit) + .with(ChronoField.HOUR_OF_DAY, 23) + .with(ChronoField.MINUTE_OF_HOUR, 59) + .with(ChronoField.SECOND_OF_MINUTE, 59); + } + var subscription = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream().findFirst().orElseThrow(); + var updatedSubscriptions = subscriptionRepository.confirmSubscription(reservationId, + status, + requireNonNullElse(subscription.getFirstName(), customerName.getFirstName()), + requireNonNullElse(subscription.getLastName(), customerName.getLastName()), + requireNonNullElse(subscription.getEmail(), email), + subscriptionDescriptor.getMaxEntries(), + validityFrom, + validityTo, + confirmationTimestamp, + subscriptionDescriptor.getTimeZone()); + Validate.isTrue(updatedSubscriptions > 0, "must have updated at least one subscription"); + subscription = subscriptionRepository.findSubscriptionsByReservationId(reservationId).get(0); // at the moment it's safe because there can be only one subscription per reservation + var subscriptionId = subscription.getId(); + auditingRepository.insert(reservationId, null, purchaseContext, SUBSCRIPTION_ACQUIRED, new Date(), Audit.EntityType.SUBSCRIPTION, subscriptionId.toString()); + extensionManager.handleSubscriptionAssignmentMetadata(subscription, subscriptionDescriptor, subscriptionRepository.getSubscriptionMetadata(subscriptionId)) + .ifPresent(metadata -> subscriptionRepository.setMetadataForSubscription(subscriptionId, metadata)); + } + + private void acquireEventTickets(PaymentProxy paymentProxy, String reservationId, PurchaseContext purchaseContext, Event event) { + Ticket.TicketStatus ticketStatus = paymentProxy.isDeskPaymentRequired() ? Ticket.TicketStatus.TO_BE_PAID : Ticket.TicketStatus.ACQUIRED; + AdditionalServiceItem.AdditionalServiceItemStatus asStatus = paymentProxy.isDeskPaymentRequired() ? AdditionalServiceItem.AdditionalServiceItemStatus.TO_BE_PAID : AdditionalServiceItem.AdditionalServiceItemStatus.ACQUIRED; + Map preUpdateTicket = ticketRepository.findTicketsInReservation(reservationId).stream().collect(toMap(Ticket::getId, Function.identity())); + int updatedTickets = ticketRepository.updateTicketsStatusWithReservationId(reservationId, ticketStatus.toString()); + if(!configurationManager.getFor(ENABLE_TICKET_TRANSFER, purchaseContext.getConfigurationLevel()).getValueAsBooleanOrDefault()) { + //automatically lock assignment + int locked = ticketRepository.forbidReassignment(preUpdateTicket.keySet()); + Validate.isTrue(updatedTickets == locked, "Expected to lock "+updatedTickets+" tickets, locked "+ locked); + Map postUpdateTicket = ticketRepository.findTicketsInReservation(reservationId).stream().collect(toMap(Ticket::getId, Function.identity())); + + postUpdateTicket.forEach( + (id, ticket) -> auditingHelper.auditUpdateTicket(preUpdateTicket.get(id), Collections.emptyMap(), ticket, Collections.emptyMap(), event.getId())); + } + var ticketsWithMetadataById = ticketRepository.findTicketsInReservationWithMetadata(reservationId) + .stream().collect(toMap(twm -> twm.getTicket().getId(), Function.identity())); + ticketsWithMetadataById.forEach((id, ticketWithMetadata) -> { + var newMetadataOptional = extensionManager.handleTicketAssignmentMetadata(ticketWithMetadata, event); + newMetadataOptional.ifPresent(metadata -> { + var existingContainer = TicketMetadataContainer.copyOf(ticketWithMetadata.getMetadata()); + var general = new HashMap<>(existingContainer.getMetadataForKey(TicketMetadataContainer.GENERAL) + .orElseGet(TicketMetadata::empty).getAttributes()); + general.putAll(metadata.getAttributes()); + existingContainer.putMetadata(TicketMetadataContainer.GENERAL, new TicketMetadata(null, null, general)); + ticketRepository.updateTicketMetadata(id, existingContainer); + auditingHelper.auditUpdateMetadata(reservationId, id, event.getId(), existingContainer, ticketWithMetadata.getMetadata()); + }); + auditingHelper.auditUpdateTicket(preUpdateTicket.get(id), Collections.emptyMap(), ticketWithMetadata.getTicket(), Collections.emptyMap(), event.getId()); + }); + int updatedAS = additionalServiceItemRepository.updateItemsStatusWithReservationUUID(reservationId, asStatus); + Validate.isTrue(updatedTickets + updatedAS > 0, "no items have been updated"); + } + + public void confirmOfflinePayment(Event event, + String reservationId, + TransactionMetadataModification transactionMetadataModification, + String username) { + TicketReservation ticketReservation = findById(reservationId).orElseThrow(IllegalArgumentException::new); + ticketReservationRepository.lockReservationForUpdate(reservationId); + var metadata = ticketReservationRepository.getMetadata(reservationId); + if (!metadata.isReadyForConfirmation()) { + throw new IncompatibleStateException("Reservation is not ready to be confirmed"); + } + Validate.isTrue(ticketReservation.getPaymentMethod() == PaymentProxy.OFFLINE, "invalid payment method"); + Validate.isTrue(ticketReservation.isPendingOfflinePayment(), "invalid status"); + + + ticketReservationRepository.confirmOfflinePayment(reservationId, COMPLETE.name(), event.now(clockProvider)); + + registerAlfioTransaction(event, reservationId, transactionMetadataModification, PaymentProxy.OFFLINE); + + auditingRepository.insert(reservationId, userRepository.findIdByUserName(username).orElse(null), event.getId(), Audit.EventType.RESERVATION_OFFLINE_PAYMENT_CONFIRMED, new Date(), Audit.EntityType.RESERVATION, ticketReservation.getId()); + + ticketReservationRepository.setMetadata(reservationId, metadata.withFinalized(true)); + CustomerName customerName = new CustomerName(ticketReservation.getFullName(), ticketReservation.getFirstName(), ticketReservation.getLastName(), event.mustUseFirstAndLastName()); + acquireItems(PaymentProxy.OFFLINE, reservationId, ticketReservation.getEmail(), customerName, + ticketReservation.getUserLanguage(), ticketReservation.getBillingAddress(), + ticketReservation.getCustomerReference(), event, true); + + Locale language = ReservationUtil.getReservationLocale(ticketReservation); + final TicketReservation finalReservation = ticketReservationRepository.findReservationById(reservationId); + billingDocumentManager.createBillingDocument(event, finalReservation, username, orderSummaryGenerator.orderSummaryForReservation(finalReservation, event)); + var configuration = configurationManager.getFor(EnumSet.of(DEFERRED_BANK_TRANSFER_ENABLED, DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL), ConfigurationLevel.event(event)); + if(!configuration.get(DEFERRED_BANK_TRANSFER_ENABLED).getValueAsBooleanOrDefault() || configuration.get(DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL).getValueAsBooleanOrDefault()) { + reservationHelper.sendConfirmationEmail(event, findById(reservationId).orElseThrow(IllegalArgumentException::new), language, username); + } + extensionManager.handleReservationConfirmation(finalReservation, ticketReservationRepository.getBillingDetailsForReservation(reservationId), event); + } + + public void registerAlfioTransaction(Event event, + String reservationId, + TransactionMetadataModification transactionMetadataModification, + PaymentProxy paymentProxy) { + var totalPrice = reservationCostCalculator.totalReservationCostWithVAT(reservationId).getLeft(); + int priceWithVAT = totalPrice.priceWithVAT(); + long platformFee = FeeCalculator.getCalculator(event, configurationManager, requireNonNullElse(totalPrice.currencyCode(), event.getCurrency())) + .apply(ticketRepository.countTicketsInReservation(reservationId), (long) priceWithVAT) + .orElse(0L); + + //FIXME we must support multiple transactions for a reservation, otherwise we can't handle properly the case of ON_SITE payments + + var transactionOptional = transactionRepository.loadOptionalByReservationId(reservationId); + String transactionId = paymentProxy.getKey() + "-" + System.currentTimeMillis(); + var transactionTimestamp = getTransactionTimestamp(event, transactionMetadataModification); + if(transactionOptional.isEmpty()) { + transactionRepository.insert(transactionId, null, reservationId, transactionTimestamp, + priceWithVAT, event.getCurrency(), "Offline payment confirmed for "+reservationId, paymentProxy.getKey(), + platformFee, 0L, Transaction.Status.COMPLETE, buildTransactionMetadata(transactionMetadataModification)); + } else if(paymentProxy == PaymentProxy.OFFLINE) { + var transaction = transactionOptional.get(); + transactionRepository.update(transaction.getId(), transactionId, null, transactionTimestamp, + platformFee, 0L, Transaction.Status.COMPLETE, buildTransactionMetadata(transactionMetadataModification)); + } else { + log.warn("ON-Site check-in: ignoring transaction registration for reservationId {}", reservationId); + } + } + + private ZonedDateTime getTransactionTimestamp(Event event, TransactionMetadataModification transactionMetadataModification) { + if (transactionMetadataModification != null && transactionMetadataModification.getTimestamp() != null) { + return transactionMetadataModification.getTimestamp().toLocalDateTime().atZone(event.getZoneId()); + } + return event.now(clockProvider); + } + + private Map buildTransactionMetadata(TransactionMetadataModification transactionMetadataModification) { + if (transactionMetadataModification != null && StringUtils.isNotBlank(transactionMetadataModification.getNotes())) { + return Map.of(Transaction.NOTES_KEY, transactionMetadataModification.getNotes()); + } + return Map.of(); + } + + private Optional findById(String reservationId) { + return ticketReservationRepository.findOptionalReservationById(reservationId); + } + + private List findTicketsInReservation(String reservationId) { + return ticketRepository.findTicketsInReservation(reservationId); + } + + +} diff --git a/src/main/java/alfio/manager/ReverseChargeManager.java b/src/main/java/alfio/manager/ReverseChargeManager.java index c7c5f0944c..59061e82a7 100644 --- a/src/main/java/alfio/manager/ReverseChargeManager.java +++ b/src/main/java/alfio/manager/ReverseChargeManager.java @@ -17,11 +17,17 @@ package alfio.manager; import alfio.controller.form.ContactAndTicketsForm; +import alfio.controller.support.CustomBindingResult; import alfio.manager.system.ConfigurationManager; import alfio.manager.system.ReservationPriceCalculator; import alfio.model.*; +import alfio.model.decorator.TicketPriceContainer; +import alfio.model.extension.CustomTaxPolicy; import alfio.repository.*; -import lombok.AllArgsConstructor; +import alfio.util.MonetaryUtil; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; @@ -29,23 +35,23 @@ import org.springframework.validation.ValidationUtils; import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import static alfio.model.Audit.EntityType.RESERVATION; import static alfio.model.PriceContainer.VatStatus.*; -import static alfio.model.PriceContainer.VatStatus.NOT_INCLUDED_NOT_CHARGED; import static alfio.model.system.ConfigurationKeys.*; import static alfio.util.MonetaryUtil.unitToCents; import static java.util.stream.Collectors.toMap; import static org.apache.commons.lang3.StringUtils.trimToNull; -@AllArgsConstructor @Component public class ReverseChargeManager { + private static final Logger log = LoggerFactory.getLogger(ReverseChargeManager.class); private final PromoCodeDiscountRepository promoCodeDiscountRepository; private final AdditionalServiceItemRepository additionalServiceItemRepository; private final AdditionalServiceRepository additionalServiceRepository; @@ -57,8 +63,33 @@ public class ReverseChargeManager { private final TicketReservationManager ticketReservationManager; private final TicketRepository ticketRepository; private final SubscriptionRepository subscriptionRepository; - - + private final AuditingRepository auditingRepository; + + public ReverseChargeManager(PromoCodeDiscountRepository promoCodeDiscountRepository, + AdditionalServiceItemRepository additionalServiceItemRepository, + AdditionalServiceRepository additionalServiceRepository, + TicketCategoryRepository ticketCategoryRepository, + NamedParameterJdbcTemplate jdbcTemplate, + ConfigurationManager configurationManager, + TicketReservationRepository ticketReservationRepository, + EuVatChecker vatChecker, + TicketReservationManager ticketReservationManager, + TicketRepository ticketRepository, + SubscriptionRepository subscriptionRepository, + AuditingRepository auditingRepository) { + this.promoCodeDiscountRepository = promoCodeDiscountRepository; + this.additionalServiceItemRepository = additionalServiceItemRepository; + this.additionalServiceRepository = additionalServiceRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.jdbcTemplate = jdbcTemplate; + this.configurationManager = configurationManager; + this.ticketReservationRepository = ticketReservationRepository; + this.vatChecker = vatChecker; + this.ticketReservationManager = ticketReservationManager; + this.ticketRepository = ticketRepository; + this.subscriptionRepository = subscriptionRepository; + this.auditingRepository = auditingRepository; + } public void checkAndApplyVATRules(PurchaseContext purchaseContext, @@ -88,85 +119,179 @@ public void checkAndApplyVATRules(PurchaseContext purchaseContext, .map(res -> ticketCategoryRepository.findCategoriesInReservation(res.getId())) .orElse(List.of()); - Optional vatDetail = optionalReservation - .filter(e -> { - if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) && (!reverseChargeInPerson || !reverseChargeOnline)) { - var eventFormat = purchaseContext.event().orElseThrow().getFormat(); - // if we find at least one category matching the criteria, then we can proceed - return categoriesList.stream().anyMatch(findReverseChargeCategory(reverseChargeInPerson, reverseChargeOnline, eventFormat)); - } - var vatStatus = purchaseContext.getVatStatus(); - return vatStatus == INCLUDED || vatStatus == NOT_INCLUDED; - }) - .filter(e -> vatChecker.isReverseChargeEnabledFor(purchaseContext)) - .flatMap(e -> vatChecker.checkVat(contactAndTicketsForm.getVatNr(), country, purchaseContext)); + List noTaxCategories = new ArrayList<>(); + if (!categoriesList.isEmpty()) { + noTaxCategories.addAll(configurationManager.getCategoriesWithNoTaxes(categoriesList.stream().map(TicketCategory::getId).collect(Collectors.toList()))); + } + Optional vatDetail = performReverseChargeCheck(purchaseContext, contactAndTicketsForm, country, reverseChargeInPerson, reverseChargeOnline, optionalReservation, categoriesList); if(vatDetail.isPresent()) { - var vatValidation = vatDetail.get(); - if (!vatValidation.isValid()) { - bindingResult.rejectValue("vatNr", "error.STEP_2_INVALID_VAT"); - } else { - var reservation = ticketReservationManager.findById(reservationId).orElseThrow(); - var currencyCode = reservation.getCurrencyCode(); - PriceContainer.VatStatus vatStatus = determineVatStatus(purchaseContext.getVatStatus(), vatValidation.isVatExempt()); - // standard case: Reverse Charge is applied to the entire reservation - var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null; - if(!isEvent || (reverseChargeOnline && reverseChargeInPerson)) { - if(isEvent) { - var event = purchaseContext.event().orElseThrow(); - var priceContainers = mapPriceContainersByCategoryId(categoriesList, - (a) -> true, - currencyCode, - vatStatus, - discount, - event); - // update all tickets in reservation to match the VAT_STATUS - ticketRepository.updateVatStatusForReservation(reservationId, vatStatus); - updateTicketPricesByCategory(reservationId, currencyCode, vatStatus, event, priceContainers); - } - updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, country, trimToNull(vatValidation.getVatNr()), reservation, vatStatus); - } else { - var event = purchaseContext.event().orElseThrow(); - var eventFormat = event.getFormat(); - var matchingCategories = mapPriceContainersByCategoryId(categoriesList, - findReverseChargeCategory(reverseChargeInPerson, reverseChargeOnline, eventFormat), - currencyCode, - vatStatus, - discount, - event); - - updateTicketPricesByCategory(reservationId, currencyCode, vatStatus, event, matchingCategories); - // update billing data for the reservation, using the original VatStatus from reservation - updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, country, trimToNull(vatValidation.getVatNr()), reservation, reservation.getVatStatus()); - } - vatChecker.logSuccessfulValidation(vatValidation, reservationId, purchaseContext); - } - } else if(optionalReservation.isPresent() && contactAndTicketsForm.isItalyEInvoicingSplitPayment()) { + handleValidationResult(purchaseContext, reservationId, contactAndTicketsForm, bindingResult, country, isEvent, reverseChargeInPerson, reverseChargeOnline, categoriesList, noTaxCategories, vatDetail.get()); + } else if (optionalReservation.isPresent() && contactAndTicketsForm.isItalyEInvoicingSplitPayment()) { + handleSplitPayment(purchaseContext, reservationId, contactAndTicketsForm, country, optionalReservation.get(), categoriesList, noTaxCategories); + } else if (optionalReservation.isPresent() && !noTaxCategories.isEmpty()) { + // if there is at least one category with custom tax policy, we need to update its tickets var reservation = optionalReservation.get(); - var vatStatus = purchaseContext.getVatStatus() == INCLUDED ? INCLUDED_NOT_CHARGED : NOT_INCLUDED_NOT_CHARGED; - updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, country, trimToNull(contactAndTicketsForm.getVatNr()), reservation, vatStatus); + updateTicketsWithNoTaxSetting(purchaseContext, reservationId, reservation, categoriesList, noTaxCategories); + updateBillingData(contactAndTicketsForm, purchaseContext, country, trimToNull(contactAndTicketsForm.getVatNr()), reservation, reservation.getVatStatus()); } } catch (IllegalStateException ise) {//vat checker failure bindingResult.rejectValue("vatNr", "error.vatVIESDown"); } } + private Optional performReverseChargeCheck(PurchaseContext purchaseContext, ContactAndTicketsForm contactAndTicketsForm, String country, boolean reverseChargeInPerson, boolean reverseChargeOnline, Optional optionalReservation, List categoriesList) { + return optionalReservation + .filter(e -> { + if (purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) && (!reverseChargeInPerson || !reverseChargeOnline)) { + var eventFormat = purchaseContext.event().orElseThrow().getFormat(); + // if we find at least one category matching the criteria, then we can proceed + return categoriesList.stream().anyMatch(findReverseChargeCategory(reverseChargeInPerson, reverseChargeOnline, eventFormat)); + } + var vatStatus = purchaseContext.getVatStatus(); + return vatStatus == INCLUDED || vatStatus == NOT_INCLUDED; + }) + .filter(e -> vatChecker.isReverseChargeEnabledFor(purchaseContext)) + .flatMap(e -> vatChecker.checkVat(contactAndTicketsForm.getVatNr(), country, purchaseContext)); + } + + private void updateTicketsWithNoTaxSetting(PurchaseContext purchaseContext, + String reservationId, + TicketReservation reservation, + List categoriesList, + List noTaxCategories) { + if (purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + var currencyCode = reservation.getCurrencyCode(); + var event = purchaseContext.event().orElseThrow(); + var priceContainers = mapPriceContainersByCategoryId(categoriesList, + c -> noTaxCategories.contains(c.getId()), + currencyCode, + reservation.getVatStatus(), + reservation.getDiscount().orElse(null), + event, + noTaxCategories); + updateTicketPricesByCategory(reservationId, currencyCode, event, priceContainers); + } + } + + private void handleSplitPayment(PurchaseContext purchaseContext, String reservationId, ContactAndTicketsForm contactAndTicketsForm, String country, TicketReservation reservation, List categoriesList, List noTaxCategories) { + updateTicketsWithNoTaxSetting(purchaseContext, reservationId, reservation, categoriesList, noTaxCategories); + var vatStatus = purchaseContext.getVatStatus() == INCLUDED ? INCLUDED_NOT_CHARGED : NOT_INCLUDED_NOT_CHARGED; + updateBillingData(contactAndTicketsForm, purchaseContext, country, trimToNull(contactAndTicketsForm.getVatNr()), reservation, vatStatus); + } + + private void handleValidationResult(PurchaseContext purchaseContext, String reservationId, ContactAndTicketsForm contactAndTicketsForm, BindingResult bindingResult, String country, boolean isEvent, boolean reverseChargeInPerson, boolean reverseChargeOnline, List categoriesList, List noTaxCategories, VatDetail vatValidation) { + if (!vatValidation.isValid()) { + bindingResult.rejectValue("vatNr", "error.STEP_2_INVALID_VAT"); + } else { + var reservation = ticketReservationManager.findById(reservationId).orElseThrow(); + var currencyCode = reservation.getCurrencyCode(); + PriceContainer.VatStatus vatStatus = determineVatStatus(purchaseContext.getVatStatus(), vatValidation.isVatExempt()); + // standard case: Reverse Charge is applied to the entire reservation + var discount = getDiscountOrNull(reservation); + if(!isEvent || (reverseChargeOnline && reverseChargeInPerson)) { + if(isEvent) { + var event = purchaseContext.event().orElseThrow(); + var priceContainers = mapPriceContainersByCategoryId(categoriesList, + a -> true, + currencyCode, + vatStatus, + discount, + event, + noTaxCategories); + // update all tickets in reservation to match the VAT_STATUS + ticketRepository.updateVatStatusForReservation(reservationId, vatStatus); + updateTicketPricesByCategory(reservationId, currencyCode, event, priceContainers); + } + updateBillingData(contactAndTicketsForm, purchaseContext, country, trimToNull(vatValidation.getVatNr()), reservation, vatStatus); + } else { + var event = purchaseContext.event().orElseThrow(); + var eventFormat = event.getFormat(); + var matchingCategories = mapPriceContainersByCategoryId(categoriesList, + findReverseChargeCategory(reverseChargeInPerson, reverseChargeOnline, eventFormat), + currencyCode, + vatStatus, + discount, + event, + noTaxCategories); + + updateTicketPricesByCategory(reservationId, currencyCode, event, matchingCategories); + // update billing data for the reservation, using the original VatStatus from reservation + updateBillingData(contactAndTicketsForm, purchaseContext, country, trimToNull(vatValidation.getVatNr()), reservation, reservation.getVatStatus()); + } + vatChecker.logSuccessfulValidation(vatValidation, reservationId, purchaseContext); + } + } + + private PromoCodeDiscount getDiscountOrNull(TicketReservation reservation) { + if (reservation.getPromoCodeDiscountId() != null) { + return promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()); + } + return null; + } + + public void applyCustomTaxPolicy(PurchaseContext purchaseContext, + CustomTaxPolicy customTaxPolicy, + String reservationId, + ContactAndTicketsForm contactAndTicketsForm, + CustomBindingResult bindingResult) { + + if (!purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + throw new IllegalStateException("Custom tax policy is only supported for events"); + } + + var event = (Event) purchaseContext; + // first, validate that categories in CustomTaxPolicy are actually present in the form + var reservation = ticketReservationManager.findById(reservationId).orElseThrow(); + var currencyCode = reservation.getCurrencyCode(); + var ticketsInReservation = ticketRepository.findTicketsInReservation(reservationId).stream() + .collect(toMap(Ticket::getUuid, Function.identity())); + var ticketIds = ticketsInReservation.keySet(); + if (customTaxPolicy.getTicketPolicies().stream().anyMatch(tp -> !ticketIds.contains(tp.getUuid()))) { + log.warn("Error in custom tax policy: some tickets are not included in reservation {}", reservationId); + bindingResult.reject("error.generic"); + } else { + // log the received policy to the auditing + auditingRepository.insert(reservationId, null, purchaseContext, Audit.EventType.VAT_CUSTOM_CONFIGURATION_APPLIED, new Date(), RESERVATION, reservationId, List.of(Map.of("policy", customTaxPolicy))); + var priceMapping = customTaxPolicy.getTicketPolicies().stream() + .map(tcp -> toTicketPriceContainer(ticketsInReservation.get(tcp.getUuid()), tcp, getDiscountOrNull(reservation), event)) + .collect(Collectors.toList()); + updateTicketPrices(priceMapping, currencyCode, event); + // update billing data for the reservation, using the original VatStatus from reservation + updateBillingData(contactAndTicketsForm, purchaseContext, reservation.getVatCountryCode(), trimToNull(reservation.getVatNr()), reservation, reservation.getVatStatus()); + } + } + + private static TicketPriceContainer toTicketPriceContainer(Ticket ticket, + CustomTaxPolicy.TicketTaxPolicy categoryTaxPolicy, + PromoCodeDiscount discount, + Event event) { + return TicketPriceContainer.from( + ticket.withVatStatus(categoryTaxPolicy.getTaxPolicy()), + categoryTaxPolicy.getTaxPolicy(), + event.getVat(), + event.getVatStatus(), + discount + ); + } + public void resetVat(PurchaseContext purchaseContext, String reservationId) { if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { var reservation = ticketReservationRepository.findReservationById(reservationId); var categoriesList = ticketCategoryRepository.findCategoriesInReservation(reservationId); - var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null; + var discount = getDiscountOrNull(reservation); var event = purchaseContext.event().orElseThrow(); var priceContainers = mapPriceContainersByCategoryId(categoriesList, (a) -> true, reservation.getCurrencyCode(), reservation.getVatStatus(), discount, - event); + event, + List.of()); // update all tickets in reservation to match the VAT_STATUS ticketRepository.updateVatStatusForReservation(reservationId, reservation.getVatStatus()); - updateTicketPricesByCategory(reservationId, reservation.getCurrencyCode(), reservation.getVatStatus(), event, priceContainers); + updateTicketPricesByCategory(reservationId, reservation.getCurrencyCode(), event, priceContainers); } } @@ -175,36 +300,56 @@ private Map mapPriceContainersByCategoryI String currencyCode, PriceContainer.VatStatus vatStatus, PromoCodeDiscount discount, - Event event) { + Event event, + List noTaxCategories) { return categoriesList.stream() .filter(filter) - .map(c -> new TicketCategoryPriceContainer(c.getId(), c.getSrcPriceCts(), currencyCode, event.getVat(), vatStatus, discount)) + .map(c -> { + var categoryVatStatus = vatStatus; + if (noTaxCategories.contains(c.getId())) { + categoryVatStatus = PriceContainer.VatStatus.forceExempt(vatStatus); + } + return new TicketCategoryPriceContainer(c.getId(), c.getSrcPriceCts(), currencyCode, event.getVat(), categoryVatStatus, discount); + }) .collect(toMap(o -> o.categoryId, Function.identity())); } private void updateTicketPricesByCategory(String reservationId, String currencyCode, - PriceContainer.VatStatus vatStatus, Event event, Map matchingCategories) { MapSqlParameterSource[] parameterSources = matchingCategories.entrySet().stream() - .map(entry -> { - var value = entry.getValue(); - return new MapSqlParameterSource() - .addValue("reservationId", reservationId) - .addValue("categoryId", entry.getKey()) - .addValue("eventId", event.getId()) - .addValue("srcPriceCts", value.getSrcPriceCts()) - .addValue("finalPriceCts", value.getFinalPriceCts()) - .addValue("vatCts", value.getVatCts()) - .addValue("discountCts", value.getDiscountCts()) - .addValue("currencyCode", currencyCode) - .addValue("vatStatus", vatStatus.name()); - } - ).toArray(MapSqlParameterSource[]::new); + .map(entry -> buildParameterSourceForPriceUpdate(entry.getValue(), event.getId(), entry.getKey(), currencyCode, + m -> m.addValue("reservationId", reservationId))) + .toArray(MapSqlParameterSource[]::new); jdbcTemplate.batchUpdate(ticketRepository.updateTicketPriceForCategoryInReservation(), parameterSources); } + private void updateTicketPrices(List ticketPrices, String currencyCode, Event event) { + MapSqlParameterSource[] parameterSources = ticketPrices.stream() + .map(entry -> buildParameterSourceForPriceUpdate(entry, event.getId(), entry.getCategoryId(), currencyCode, + m -> m.addValue("uuid", entry.getUuid()))) + .toArray(MapSqlParameterSource[]::new); + var updateResult = jdbcTemplate.batchUpdate(ticketRepository.bulkUpdateTicketPrice(), parameterSources); + Validate.isTrue(Arrays.stream(updateResult).allMatch(i -> i == 1), "Error while updating ticket prices"); + } + + private static MapSqlParameterSource buildParameterSourceForPriceUpdate(PriceContainer value, + int eventId, + int categoryId, + String currencyCode, + UnaryOperator modifier) { + return modifier.apply(new MapSqlParameterSource() + .addValue("categoryId", categoryId) + .addValue("eventId", eventId) + .addValue("srcPriceCts", value.getSrcPriceCts()) + .addValue("finalPriceCts", MonetaryUtil.unitToCents(value.getFinalPrice(), currencyCode)) + .addValue("vatCts", MonetaryUtil.unitToCents(value.getVAT(), currencyCode)) + .addValue("discountCts", MonetaryUtil.unitToCents(value.getAppliedDiscount(), currencyCode)) + .addValue("currencyCode", currencyCode) + .addValue("vatStatus", value.getVatStatus().name())); + } + private Predicate findReverseChargeCategory(boolean reverseChargeInPerson, boolean reverseChargeOnline, Event.EventFormat eventFormat) { return tc -> { if (eventFormat == Event.EventFormat.HYBRID) { @@ -215,8 +360,9 @@ private Predicate findReverseChargeCategory(boolean reverseCharg }; } - private void updateBillingData(String reservationId, ContactAndTicketsForm contactAndTicketsForm, PurchaseContext purchaseContext, String country, String vatNr, TicketReservation reservation, PriceContainer.VatStatus vatStatus) { - var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null; + private void updateBillingData(ContactAndTicketsForm contactAndTicketsForm, PurchaseContext purchaseContext, String country, String vatNr, TicketReservation reservation, PriceContainer.VatStatus vatStatus) { + var reservationId = reservation.getId(); + var discount = getDiscountOrNull(reservation); var additionalServiceItems = additionalServiceItemRepository.findByReservationUuid(reservation.getId()); var tickets = ticketReservationManager.findTicketsInReservation(reservation.getId()); var additionalServices = purchaseContext.event().map(event -> additionalServiceRepository.loadAllForEvent(event.getId())).orElse(List.of()); diff --git a/src/main/java/alfio/manager/SameCountryValidator.java b/src/main/java/alfio/manager/SameCountryValidator.java index 5b9c2ce5b6..5399c127fd 100644 --- a/src/main/java/alfio/manager/SameCountryValidator.java +++ b/src/main/java/alfio/manager/SameCountryValidator.java @@ -17,22 +17,20 @@ package alfio.manager; import alfio.manager.system.ConfigurationManager; -import alfio.model.Event; -import alfio.model.EventAndOrganizationId; import alfio.model.PurchaseContext; import alfio.model.VatDetail; import ch.digitalfondue.vatchecker.EUVatCheckResponse; import ch.digitalfondue.vatchecker.EUVatChecker; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.function.Predicate; -@RequiredArgsConstructor -@Log4j2 public class SameCountryValidator implements Predicate { + private static final Logger log = LoggerFactory.getLogger(SameCountryValidator.class); + private final ConfigurationManager configurationManager; private final ExtensionManager extensionManager; private final PurchaseContext purchaseContext; @@ -40,6 +38,18 @@ public class SameCountryValidator implements Predicate { private final EuVatChecker checker; private final EUVatChecker client = new EUVatChecker(); + public SameCountryValidator(ConfigurationManager configurationManager, + ExtensionManager extensionManager, + PurchaseContext purchaseContext, + String ticketReservationId, + EuVatChecker checker) { + this.configurationManager = configurationManager; + this.extensionManager = extensionManager; + this.purchaseContext = purchaseContext; + this.ticketReservationId = ticketReservationId; + this.checker = checker; + } + @Override public boolean test(String vatNr) { diff --git a/src/main/java/alfio/manager/SpecialPriceManager.java b/src/main/java/alfio/manager/SpecialPriceManager.java index 0aec6a04d9..f94cc31aa5 100644 --- a/src/main/java/alfio/manager/SpecialPriceManager.java +++ b/src/main/java/alfio/manager/SpecialPriceManager.java @@ -27,7 +27,6 @@ import alfio.util.LocaleUtil; import alfio.util.TemplateManager; import alfio.util.TemplateResource; -import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.springframework.stereotype.Component; @@ -38,10 +37,8 @@ import java.util.stream.Stream; import static alfio.model.system.ConfigurationKeys.USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL; -import static java.util.stream.Collectors.toList; @Component -@AllArgsConstructor @Transactional public class SpecialPriceManager { @@ -55,15 +52,33 @@ public class SpecialPriceManager { private final ConfigurationManager configurationManager; private final ClockProvider clockProvider; + public SpecialPriceManager(EventManager eventManager, + NotificationManager notificationManager, + SpecialPriceRepository specialPriceRepository, + TemplateManager templateManager, + MessageSourceManager messageSourceManager, + I18nManager i18nManager, + ConfigurationManager configurationManager, + ClockProvider clockProvider) { + this.eventManager = eventManager; + this.notificationManager = notificationManager; + this.specialPriceRepository = specialPriceRepository; + this.templateManager = templateManager; + this.messageSourceManager = messageSourceManager; + this.i18nManager = i18nManager; + this.configurationManager = configurationManager; + this.clockProvider = clockProvider; + } + private List checkCodeAssignment(Set input, int categoryId, EventAndOrganizationId event, String username) { final TicketCategory category = checkOwnership(categoryId, event, username); List availableCodes = specialPriceRepository.findActiveByCategoryIdForUpdate(category.getId(), input.size()) .stream() - .map(SpecialPrice::getCode).collect(toList()); + .map(SpecialPrice::getCode).toList(); Validate.isTrue(input.size() <= availableCodes.size(), "Requested codes: "+input.size()+ ", available: "+availableCodes.size()+"."); - List requestedCodes = input.stream().filter(IS_CODE_PRESENT).map(SendCodeModification::getCode).collect(toList()); + List requestedCodes = input.stream().filter(IS_CODE_PRESENT).map(SendCodeModification::getCode).toList(); Validate.isTrue(requestedCodes.stream().distinct().count() == requestedCodes.size(), "Cannot assign the same code twice. Please fix the input file."); - Validate.isTrue(availableCodes.containsAll(requestedCodes), "some requested codes don't exist."); + Validate.isTrue(new HashSet<>(availableCodes).containsAll(requestedCodes), "some requested codes don't exist."); return availableCodes; } @@ -82,14 +97,14 @@ public List linkAssigneeToCode(List final Iterator codes = availableCodes.iterator(); return Stream.concat(set.stream().filter(IS_CODE_PRESENT), input.stream().filter(IS_CODE_PRESENT.negate()) .map(p -> new SendCodeModification(codes.next(), p.getAssignee(), p.getEmail(), p.getLanguage()))) - .collect(toList()); + .toList(); } public List loadSentCodes(String eventName, int categoryId, String username) { final EventAndOrganizationId event = eventManager.getEventAndOrganizationId(eventName, username); checkOwnership(categoryId, event, username); Predicate p = SpecialPrice::notSent; - return specialPriceRepository.findAllByCategoryId(categoryId).stream().filter(p.negate()).collect(toList()); + return specialPriceRepository.findAllByCategoryId(categoryId).stream().filter(p.negate()).toList(); } public boolean clearRecipientData(String eventName, int categoryId, int codeId, String username) { diff --git a/src/main/java/alfio/manager/SpecialPriceTokenGenerator.java b/src/main/java/alfio/manager/SpecialPriceTokenGenerator.java index 82bff9ad6d..dfd4decc7c 100644 --- a/src/main/java/alfio/manager/SpecialPriceTokenGenerator.java +++ b/src/main/java/alfio/manager/SpecialPriceTokenGenerator.java @@ -25,9 +25,10 @@ import alfio.repository.EventRepository; import alfio.repository.SpecialPriceRepository; import alfio.repository.TicketCategoryRepository; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.time.StopWatch; import org.apache.commons.text.RandomStringGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Component; @@ -41,10 +42,11 @@ * granting a special price to a specific user category. */ @Component -@Log4j2 @Transactional public class SpecialPriceTokenGenerator { + private static final Logger log = LoggerFactory.getLogger(SpecialPriceTokenGenerator.class); + private static final SecureRandom RANDOM = new SecureRandom(); private static final char[] ADMITTED_CHARACTERS = new char[]{ 'A', 'B', 'C', 'D', 'E', 'F', diff --git a/src/main/java/alfio/manager/SubscriptionManager.java b/src/main/java/alfio/manager/SubscriptionManager.java index 784d7cf52b..4f0186e4db 100644 --- a/src/main/java/alfio/manager/SubscriptionManager.java +++ b/src/main/java/alfio/manager/SubscriptionManager.java @@ -16,16 +16,21 @@ */ package alfio.manager; +import alfio.config.Initializer; import alfio.controller.form.SearchOptions; import alfio.model.AllocationStatus; import alfio.model.modification.SubscriptionDescriptorModification; +import alfio.model.result.ErrorCode; +import alfio.model.result.Result; import alfio.model.subscription.EventSubscriptionLink; import alfio.model.subscription.SubscriptionDescriptor; import alfio.model.subscription.SubscriptionDescriptorWithStatistics; import alfio.repository.SubscriptionRepository; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; @@ -35,22 +40,28 @@ import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.stream.Stream; import static java.util.Objects.requireNonNullElse; @Component @Transactional -@AllArgsConstructor -@Log4j2 public class SubscriptionManager { + private static final Logger log = LoggerFactory.getLogger(SubscriptionManager.class); + private final SubscriptionRepository subscriptionRepository; private final NamedParameterJdbcTemplate jdbcTemplate; + private final Environment environment; + + public SubscriptionManager(SubscriptionRepository subscriptionRepository, + NamedParameterJdbcTemplate jdbcTemplate, + Environment environment) { + this.subscriptionRepository = subscriptionRepository; + this.jdbcTemplate = jdbcTemplate; + this.environment = environment; + } public List findAll(int organizationId) { return subscriptionRepository.findAllByOrganizationIds(organizationId); @@ -183,6 +194,12 @@ public Optional updateSubscriptionDescriptor(SubscriptionDescriptorModific if(original.getPrice() != subscriptionDescriptor.getPriceCts()) { subscriptionRepository.updatePriceForSubscriptions(subscriptionDescriptorId, subscriptionDescriptor.getPriceCts()); } + if(!Objects.equals(original.getMaxEntries(), subscriptionDescriptor.getMaxEntries())) { + int maxEntries = requireNonNullElse(subscriptionDescriptor.getMaxEntries(), -1); + int updatedSubscriptions = subscriptionRepository.updateMaxEntriesForSubscriptions(subscriptionDescriptorId, maxEntries); + log.debug("SubscriptionDescriptor #{}: updated {} subscriptions. Modified max entries to {}", + subscriptionDescriptorId, updatedSubscriptions, maxEntries); + } return Optional.of(subscriptionDescriptorId); }); } @@ -192,6 +209,9 @@ public Optional findOne(UUID id, int organizationId) { } public boolean setPublicStatus(UUID id, int organizationId, boolean isPublic) { + if(environment.acceptsProfiles(Profiles.of(Initializer.PROFILE_DEMO))) { + throw new IllegalStateException("Cannot publish subscriptions while in demo mode"); + } return subscriptionRepository.setPublicStatus(id, organizationId, isPublic) == 1; } @@ -207,6 +227,10 @@ public List loadSubscriptionsWithStatistic return subscriptionRepository.findAllWithStatistics(organizationId); } + public Optional loadSubscriptionWithStatistics(UUID id, int organizationId) { + return subscriptionRepository.findOneWithStatistics(id, organizationId); + } + public int linkSubscriptionToEvent(UUID subscriptionId, int eventId, int organizationId, int pricePerTicket) { return subscriptionRepository.linkSubscriptionAndEvent(subscriptionId, eventId, pricePerTicket, organizationId); } @@ -222,4 +246,43 @@ public int countFree(UUID subscriptionDescriptorId) { public List loadActiveSubscriptionDescriptors(int organizationId) { return subscriptionRepository.findActiveSubscriptionsForOrganization(organizationId); } + + public Result deactivateDescriptor(int organizationId, UUID descriptorId) { + // 1. remove all links + removeAllEventLinksForSubscription(organizationId, descriptorId); + int result = subscriptionRepository.deactivateDescriptor(descriptorId, organizationId); + if (result == 1) { + return Result.success(true); + } + return Result.error(ErrorCode.custom("cannot-deactivate-subscription", + "Cannot deactivate subscription descriptor")); + } + + public Result> updateLinkedEvents(int organizationId, UUID subscriptionId, List eventIds){ + if (eventIds.isEmpty()) { + removeAllEventLinksForSubscription(organizationId, subscriptionId); + return Result.success(List.of()); + } else { + subscriptionRepository.removeStaleEvents(subscriptionId, organizationId, eventIds); + var parameters = eventIds.stream() + .map(eventId -> new MapSqlParameterSource("eventId", eventId) + .addValue("subscriptionId", subscriptionId) + .addValue("pricePerTicket", 0) + .addValue("organizationId", organizationId)) + .toArray(MapSqlParameterSource[]::new); + var result = jdbcTemplate.batchUpdate(SubscriptionRepository.INSERT_SUBSCRIPTION_LINK, parameters); + return new Result.Builder>() + .checkPrecondition(() -> Arrays.stream(result).allMatch(r -> r == 1), ErrorCode.custom("cannot-link", "Cannot link events")) + .build(() -> getLinkedEvents(organizationId, subscriptionId)); + } + } + + public SubscriptionDescriptor findDescriptorBySubscriptionId(UUID subscriptionId) { + return subscriptionRepository.findDescriptorBySubscriptionId(subscriptionId); + } + + private void removeAllEventLinksForSubscription(int organizationId, UUID subscriptionId) { + int removed = subscriptionRepository.removeAllLinksForSubscription(subscriptionId, organizationId); + log.info("removed all event links ({}) for subscription {}", removed, subscriptionId); + } } diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 557e77e8d8..c464fc9e50 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -18,45 +18,38 @@ import alfio.controller.api.support.TicketHelper; import alfio.controller.form.UpdateTicketOwnerForm; -import alfio.controller.support.TemplateProcessor; import alfio.manager.PaymentManager.PaymentMethodDTO.PaymentMethodStatus; import alfio.manager.i18n.MessageSourceManager; import alfio.manager.payment.BankTransferManager; import alfio.manager.payment.PaymentSpecification; import alfio.manager.support.*; +import alfio.manager.support.reservation.*; import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; -import alfio.manager.system.Mailer; -import alfio.manager.system.ReservationPriceCalculator; import alfio.manager.user.UserManager; import alfio.model.*; import alfio.model.AdditionalServiceItem.AdditionalServiceItemStatus; import alfio.model.PriceContainer.VatStatus; import alfio.model.PromoCodeDiscount.CodeType; -import alfio.model.PromoCodeDiscount.DiscountType; import alfio.model.PurchaseContext.PurchaseContextType; import alfio.model.SpecialPrice.Status; import alfio.model.SummaryRow.SummaryType; import alfio.model.Ticket.TicketStatus; import alfio.model.TicketReservation.TicketReservationStatus; -import alfio.model.checkin.OnlineCheckInFullInfo; -import alfio.model.decorator.AdditionalServiceItemPriceContainer; +import alfio.model.checkin.CheckInFullInfo; import alfio.model.decorator.AdditionalServicePriceContainer; import alfio.model.decorator.TicketPriceContainer; -import alfio.model.extension.CustomEmailText; import alfio.model.group.LinkedGroup; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.metadata.TicketMetadata; import alfio.model.metadata.TicketMetadataContainer; -import alfio.model.modification.ASReservationWithOptionalCodeModification; -import alfio.model.modification.AdditionalServiceReservationModification; -import alfio.model.modification.TicketReservationWithOptionalCodeModification; +import alfio.model.modification.*; import alfio.model.result.ErrorCode; import alfio.model.result.Result; import alfio.model.result.WarningMessage; import alfio.model.subscription.*; -import alfio.model.subscription.SubscriptionDescriptor.SubscriptionTimeUnit; -import alfio.model.support.UserIdAndOrganizationId; -import alfio.model.system.ConfigurationKeys; +import alfio.model.system.command.FinalizeReservation; +import alfio.model.system.command.InvalidateAccess; import alfio.model.transaction.*; import alfio.model.transaction.capabilities.OfflineProcessor; import alfio.model.transaction.capabilities.ServerInitiatedTransaction; @@ -68,7 +61,6 @@ import alfio.repository.user.UserRepository; import alfio.util.*; import alfio.util.checkin.TicketCheckInUtil; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -76,6 +68,10 @@ import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.jdbc.UncategorizedSQLException; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -89,17 +85,14 @@ import org.springframework.transaction.support.TransactionTemplate; import org.springframework.util.Assert; import org.springframework.validation.BindingResult; -import org.springframework.web.util.UriComponentsBuilder; import java.math.BigDecimal; import java.security.Principal; import java.time.Clock; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.util.*; -import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.function.Predicate; @@ -108,19 +101,22 @@ import java.util.stream.Stream; import static alfio.model.Audit.EntityType.RESERVATION; -import static alfio.model.Audit.EntityType.TICKET; import static alfio.model.Audit.EventType.*; -import static alfio.model.BillingDocument.Type.*; +import static alfio.model.BillingDocument.Type.CREDIT_NOTE; import static alfio.model.PromoCodeDiscount.categoriesOrNull; import static alfio.model.TicketReservation.TicketReservationStatus.*; import static alfio.model.subscription.SubscriptionDescriptor.SubscriptionUsageType.ONCE_PER_EVENT; import static alfio.model.system.ConfigurationKeys.*; -import static alfio.util.MonetaryUtil.*; +import static alfio.util.MiscUtils.getAtIndexOrNull; +import static alfio.util.MonetaryUtil.formatUnit; +import static alfio.util.MonetaryUtil.unitToCents; +import static alfio.util.ReservationUtil.getReservationLocale; +import static alfio.util.ReservationUtil.hasPrivacyPolicy; import static alfio.util.Wrappers.optionally; import static alfio.util.checkin.TicketCheckInUtil.ticketOnlineCheckInUrl; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; +import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElse; import static java.util.stream.Collectors.*; import static org.apache.commons.lang3.StringUtils.*; @@ -129,10 +125,11 @@ @Component @Transactional -@Log4j2 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class TicketReservationManager { - + + private static final Logger log = LoggerFactory.getLogger(TicketReservationManager.class); + public static final String NOT_YET_PAID_TRANSACTION_ID = "not-paid"; private static final String STUCK_TICKETS_MSG = "there are stuck tickets for the event %s. Please check admin area."; private static final String STUCK_TICKETS_SUBJECT = "warning: stuck tickets found"; @@ -174,26 +171,12 @@ public class TicketReservationManager { private final PurchaseContextManager purchaseContextManager; private final SubscriptionRepository subscriptionRepository; private final UserManager userManager; - - public static class NotEnoughTicketsException extends RuntimeException { - - } - - public static class MissingSpecialPriceTokenException extends RuntimeException { - } - - public static class InvalidSpecialPriceTokenException extends RuntimeException { - - } - - public static class TooManyTicketsForDiscountCodeException extends RuntimeException { - } - - public static class CannotProceedWithPayment extends RuntimeException { - CannotProceedWithPayment(String message) { - super(message); - } - } + private final ApplicationEventPublisher applicationEventPublisher; + private final ReservationEmailContentHelper reservationHelper; + private final ReservationCostCalculator reservationCostCalculator; + private final OrderSummaryGenerator orderSummaryGenerator; + private final ReservationAuditingHelper auditingHelper; + private final ReservationFinalizer reservationFinalizer; public TicketReservationManager(EventRepository eventRepository, OrganizationRepository organizationRepository, @@ -226,7 +209,12 @@ public TicketReservationManager(EventRepository eventRepository, ClockProvider clockProvider, PurchaseContextManager purchaseContextManager, SubscriptionRepository subscriptionRepository, - UserManager userManager) { + UserManager userManager, + ApplicationEventPublisher applicationEventPublisher, + ReservationCostCalculator reservationCostCalculator, + ReservationEmailContentHelper reservationHelper, + ReservationFinalizer reservationFinalizer, + OrderSummaryGenerator orderSummaryGenerator) { this.eventRepository = eventRepository; this.organizationRepository = organizationRepository; this.ticketRepository = ticketRepository; @@ -264,12 +252,19 @@ public TicketReservationManager(EventRepository eventRepository, this.purchaseContextManager = purchaseContextManager; this.subscriptionRepository = subscriptionRepository; this.userManager = userManager; + this.applicationEventPublisher = applicationEventPublisher; + this.reservationCostCalculator = reservationCostCalculator; + this.orderSummaryGenerator = orderSummaryGenerator; + this.reservationHelper = reservationHelper; + this.auditingHelper = new ReservationAuditingHelper(auditingRepository); + this.reservationFinalizer = reservationFinalizer; } private String createSubscriptionReservation(SubscriptionDescriptor subscriptionDescriptor, Date reservationExpiration, Locale locale, - Integer userId) throws CannotProceedWithPayment, NotEnoughTicketsException { + Integer userId, + SubscriptionMetadata metadata) throws CannotProceedWithPayment, NotEnoughTicketsException { String reservationId = UUID.randomUUID().toString(); ticketReservationRepository.createNewReservation(reservationId, subscriptionDescriptor.now(clockProvider), @@ -281,24 +276,32 @@ private String createSubscriptionReservation(SubscriptionDescriptor subscription subscriptionDescriptor.getCurrency(), subscriptionDescriptor.getOrganizationId(), userId); + UUID subscriptionId; if(subscriptionDescriptor.getMaxAvailable() > 0) { var optionalSubscription = subscriptionRepository.selectFreeSubscription(subscriptionDescriptor.getId()); if(optionalSubscription.isEmpty()) { throw new NotEnoughTicketsException(); } - Validate.isTrue(subscriptionRepository.bindSubscriptionToReservation(reservationId, subscriptionDescriptor.getPrice(), AllocationStatus.PENDING, optionalSubscription.get()) == 1); + var subscription = optionalSubscription.get(); + Validate.isTrue(subscriptionRepository.bindSubscriptionToReservation(reservationId, subscriptionDescriptor.getPrice(), AllocationStatus.PENDING, subscription) == 1); + subscriptionId = subscription; } else { - subscriptionRepository.createSubscription(UUID.randomUUID(), subscriptionDescriptor.getId(), reservationId, subscriptionDescriptor.getMaxEntries(), + subscriptionId = UUID.randomUUID(); + subscriptionRepository.createSubscription(subscriptionId, subscriptionDescriptor.getId(), reservationId, subscriptionDescriptor.getMaxEntries(), subscriptionDescriptor.getValidityFrom(), subscriptionDescriptor.getValidityTo(), subscriptionDescriptor.getPrice(), subscriptionDescriptor.getCurrency(), subscriptionDescriptor.getOrganizationId(), AllocationStatus.PENDING, subscriptionDescriptor.getMaxEntries(), subscriptionDescriptor.getTimeZone()); } var totalPrice = totalReservationCostWithVAT(reservationId).getLeft(); var vatStatus = subscriptionDescriptor.getVatStatus(); - ticketReservationRepository.updateBillingData(subscriptionDescriptor.getVatStatus(), calculateSrcPrice(vatStatus, totalPrice), totalPrice.getPriceWithVAT(), totalPrice.getVAT(), Math.abs(totalPrice.getDiscount()), subscriptionDescriptor.getCurrency(), null, null, false, reservationId); + ticketReservationRepository.updateBillingData(subscriptionDescriptor.getVatStatus(), calculateSrcPrice(vatStatus, totalPrice), totalPrice.priceWithVAT(), totalPrice.VAT(), Math.abs(totalPrice.discount()), subscriptionDescriptor.getCurrency(), null, null, false, reservationId); auditingRepository.insert(reservationId, null, subscriptionDescriptor.event().map(Event::getId).orElse(null), Audit.EventType.RESERVATION_CREATE, new Date(), Audit.EntityType.RESERVATION, reservationId); if (!canProceedWithPayment(subscriptionDescriptor, totalPrice, reservationId)) { throw new CannotProceedWithPayment("No payment method applicable for purchase context " + subscriptionDescriptor.getType() + " with public id " + subscriptionDescriptor.getPublicIdentifier()); } + // update metadata if present + if (metadata != null) { + Validate.isTrue(subscriptionRepository.setMetadataForSubscription(subscriptionId, metadata) == 1); + } return reservationId; } @@ -359,7 +362,7 @@ public String createTicketReservation(Event event, additionalServices.forEach(as -> reserveAdditionalServicesForReservation(event.getId(), reservationId, as, discount.orElse(null))); var totalPrice = totalReservationCostWithVAT(reservationId).getLeft(); var vatStatus = event.getVatStatus(); - ticketReservationRepository.updateBillingData(event.getVatStatus(), calculateSrcPrice(vatStatus, totalPrice), totalPrice.getPriceWithVAT(), totalPrice.getVAT(), Math.abs(totalPrice.getDiscount()), event.getCurrency(), null, null, false, reservationId); + ticketReservationRepository.updateBillingData(event.getVatStatus(), calculateSrcPrice(vatStatus, totalPrice), totalPrice.priceWithVAT(), totalPrice.VAT(), Math.abs(totalPrice.discount()), event.getCurrency(), null, null, false, reservationId); auditingRepository.insert(reservationId, null, event.getId(), Audit.EventType.RESERVATION_CREATE, new Date(), Audit.EntityType.RESERVATION, reservationId); if(isDiscountCodeUsageExceeded(reservationId)) { throw new TooManyTicketsForDiscountCodeException(); @@ -401,8 +404,8 @@ Optional createDynamicPromoCodeIfNeeded(Event event, List specialPrice = fixToken(ticketReservation.getSpecialPrice(), ticketReservation.getTicketCategoryId(), event.getId(), ticketReservation); - specialPrices = specialPrice.stream().collect(toList()); + specialPrices = specialPrice.stream().toList(); } List reservedForUpdate = reserveTickets(event.getId(), ticketReservation, forWaitingQueue ? asList(TicketStatus.RELEASED, TicketStatus.PRE_RESERVED) : singletonList(TicketStatus.FREE)); @@ -433,27 +436,44 @@ void reserveTicketsForCategory(Event event, } TicketCategory category = ticketCategoryRepository.getByIdAndActive(ticketReservation.getTicketCategoryId(), event.getId()); - List> ticketMetadata = requireNonNullElse(ticketReservation.getMetadata(), List.of()); + initTicketsForReservation(event, reservationId, locale, accessCodeOrDiscount, specialPrices, reservedForUpdate, category, ticketReservation); + Ticket ticket = ticketRepository.findById(reservedForUpdate.get(0), category.getId()); + var discountToApply = ObjectUtils.firstNonNull(dynamicDiscount, accessCodeOrDiscount); + TicketPriceContainer priceContainer = TicketPriceContainer.from(ticket, null, event.getVat(), event.getVatStatus(), discountToApply); + var currencyCode = priceContainer.getCurrencyCode(); + ticketRepository.updateTicketPrice(reservedForUpdate, + category.getId(), + event.getId(), + category.getSrcPriceCts(), + MonetaryUtil.unitToCents(priceContainer.getFinalPrice(), currencyCode), + MonetaryUtil.unitToCents(priceContainer.getVAT(), currencyCode), + MonetaryUtil.unitToCents(priceContainer.getAppliedDiscount(), currencyCode), + category.getCurrencyCode(), + priceContainer.getVatStatus()); + } + + private void initTicketsForReservation(Event event, + String reservationId, + Locale locale, + PromoCodeDiscount accessCodeOrDiscount, + List specialPrices, + List reservedForUpdate, + TicketCategory category, + TicketReservationWithOptionalCodeModification ticketReservation) { + var attendees = requireNonNull(ticketReservation.getAttendees()); if (!specialPrices.isEmpty()) { if(specialPrices.size() != reservedForUpdate.size()) { throw new NotEnoughTicketsException(); } - AtomicInteger counter = new AtomicInteger(0); - var ticketsAndSpecialPrices = specialPrices.stream() - .map(sp -> { - int index = counter.getAndIncrement(); - return Triple.of(reservedForUpdate.get(index), sp, getAtIndexOrNull(ticketMetadata, index)); - }).collect(Collectors.toList()); - if(specialPrices.size() == 1) { var ticketId = reservedForUpdate.get(0); var sp = specialPrices.get(0); var accessCodeId = accessCodeOrDiscount != null && accessCodeOrDiscount.getHiddenCategoryId() != null ? accessCodeOrDiscount.getId() : null; TicketMetadata metadata = null; - var attributes = getAtIndexOrNull(ticketMetadata, 0); - if(attributes != null) { - metadata = new TicketMetadata(null, null, attributes); + var attendee = getAtIndexOrEmpty(attendees, 0); + if(attendee.hasMetadata()) { + metadata = new TicketMetadata(null, null, attendee.getMetadata()); } ticketRepository.reserveTicket(reservationId, ticketId, @@ -463,13 +483,23 @@ void reserveTicketsForCategory(Event event, category.getCurrencyCode(), event.getVatStatus(), TicketMetadataContainer.fromMetadata(metadata)); + if (attendee.hasContactData()) { + ticketRepository.updateTicketOwnerById(ticketId, attendee.getEmail(), null, attendee.getFirstName(), attendee.getLastName()); + } specialPriceRepository.updateStatus(sp.getId(), Status.PENDING.toString(), null, accessCodeId); } else { + AtomicInteger counter = new AtomicInteger(0); + var ticketsAndSpecialPrices = specialPrices.stream() + .map(sp -> { + int index = counter.getAndIncrement(); + return Triple.of(reservedForUpdate.get(index), sp, getAtIndexOrEmpty(attendees, index)); + }).toList(); jdbcTemplate.batchUpdate(ticketRepository.batchReserveTicketsForSpecialPrice(), ticketsAndSpecialPrices.stream().map( triple -> { - TicketMetadataContainer metadata = null; - if(triple.getRight() != null) { - metadata = TicketMetadataContainer.fromMetadata(new TicketMetadata(null, null, triple.getRight())); + String metadata = null; + var attendee = triple.getRight(); + if(attendee.hasMetadata()) { + metadata = json.asJsonString(TicketMetadataContainer.fromMetadata(new TicketMetadata(null, null, attendee.getMetadata()))); } return new MapSqlParameterSource(RESERVATION_ID, reservationId) .addValue("ticketId", triple.getLeft()) @@ -477,45 +507,31 @@ void reserveTicketsForCategory(Event event, .addValue("userLanguage", locale.getLanguage()) .addValue("srcPriceCts", category.getSrcPriceCts()) .addValue("currencyCode", category.getCurrencyCode()) - .addValue("ticketMetadata", json.asJsonString(metadata)) + .addValue("ticketMetadata", requireNonNullElse(metadata, "{}")) + .addValue("firstName", attendee.getFirstName()) + .addValue("lastName", attendee.getLastName()) + .addValue("email", attendee.getEmail()) .addValue("vatStatus", event.getVatStatus().toString()); } ).toArray(MapSqlParameterSource[]::new)); specialPriceRepository.batchUpdateStatus( - specialPrices.stream().map(SpecialPrice::getId).collect(toList()), + specialPrices.stream().map(SpecialPrice::getId).toList(), Status.PENDING, Objects.requireNonNull(accessCodeOrDiscount).getId()); } } else { - int reserved = ticketRepository.reserveTickets(reservationId, reservedForUpdate, category, locale.getLanguage(), event.getVatStatus(), idx -> { - var metadata = getAtIndexOrNull(ticketMetadata, idx); - if (metadata != null) { - return json.asJsonString(TicketMetadataContainer.fromMetadata(new TicketMetadata(null, null, metadata))); - } - return null; - }); + int reserved = ticketRepository.reserveTickets(reservationId, + reservedForUpdate, + category, + locale.getLanguage(), + event.getVatStatus(), + idx -> getAtIndexOrEmpty(attendees, idx)); Validate.isTrue(reserved == reservedForUpdate.size(), "Cannot reserve all tickets"); } - Ticket ticket = ticketRepository.findById(reservedForUpdate.get(0), category.getId()); - var discountToApply = ObjectUtils.firstNonNull(dynamicDiscount, accessCodeOrDiscount); - TicketPriceContainer priceContainer = TicketPriceContainer.from(ticket, null, event.getVat(), event.getVatStatus(), discountToApply); - var currencyCode = priceContainer.getCurrencyCode(); - ticketRepository.updateTicketPrice(reservedForUpdate, - category.getId(), - event.getId(), - category.getSrcPriceCts(), - MonetaryUtil.unitToCents(priceContainer.getFinalPrice(), currencyCode), - MonetaryUtil.unitToCents(priceContainer.getVAT(), currencyCode), - MonetaryUtil.unitToCents(priceContainer.getAppliedDiscount(), currencyCode), - category.getCurrencyCode(), - priceContainer.getVatStatus()); } - private static T getAtIndexOrNull(List elements, int index) { - if (elements == null || index >= elements.size()) { - return null; - } - return elements.get(index); + private static AttendeeData getAtIndexOrEmpty(List attendees, int index) { + return requireNonNullElse(getAtIndexOrNull(attendees, index), AttendeeData.empty()); } List reserveTokensForAccessCode(TicketReservationWithOptionalCodeModification ticketReservation, PromoCodeDiscount accessCode) { @@ -571,7 +587,7 @@ List reserveTickets(int eventId, TicketReservationWithOptionalCodeModif List reserveTickets(int eventId , int categoryId, int qty, List requiredStatuses) { TicketCategory category = ticketCategoryRepository.getByIdAndActive(categoryId, eventId); - List statusesAsString = requiredStatuses.stream().map(TicketStatus::name).collect(toList()); + List statusesAsString = requiredStatuses.stream().map(TicketStatus::name).toList(); if(category.isBounded()) { return ticketRepository.selectTicketInCategoryForUpdateSkipLocked(eventId, categoryId, qty, statusesAsString); } @@ -657,7 +673,7 @@ public PaymentResult performPayment(PaymentSpecification spec, if (paymentResult.isSuccessful()) { reservation = ticketReservationRepository.findReservationById(spec.getReservationId()); - transitionToComplete(spec, reservationCost, paymentProxy, null); + transitionToComplete(spec, paymentProxy, null); } else if(paymentResult.isFailed()) { reTransitionToPending(spec.getReservationId()); } @@ -667,7 +683,7 @@ public PaymentResult performPayment(PaymentSpecification spec, reTransitionToPending(spec.getReservationId()); } //it is guaranteed that in this case we're dealing with "local" error (e.g. database failure), - //thus it is safer to not rollback the reservation status + //thus it is safer to not roll back the reservation status log.error("unexpected error during payment confirmation", ex); return PaymentResult.failed("error.STEP2_STRIPE_unexpected"); } @@ -710,11 +726,9 @@ public boolean cancelPendingPayment(String reservationId, PurchaseContext purcha return false; } - private void transitionToComplete(PaymentSpecification spec, TotalPrice reservationCost, PaymentProxy paymentProxy, String username) { + private void transitionToComplete(PaymentSpecification spec, PaymentProxy paymentProxy, String username) { var status = ticketReservationRepository.findOptionalStatusAndValidationById(spec.getReservationId()).orElseThrow().getStatus(); if(status != COMPLETE) { - billingDocumentManager.generateInvoiceNumber(spec, reservationCost) - .ifPresent(invoiceNumber -> ticketReservationRepository.setInvoiceNumber(spec.getReservationId(), invoiceNumber)); completeReservation(spec, paymentProxy, true, true, username); } } @@ -748,7 +762,7 @@ private PaymentProxy evaluatePaymentProxy(PaymentProxy proxy, TotalPrice reserva if(proxy != null) { return proxy; } - if(reservationCost.getPriceWithVAT() == 0) { + if(reservationCost.priceWithVAT() == 0) { return PaymentProxy.NONE; } return PaymentProxy.STRIPE; @@ -758,7 +772,7 @@ private boolean initPaymentProcess(TotalPrice reservationCost, PaymentProxy paymentProxy, PaymentSpecification spec, Principal principal) { - if(reservationCost.getPriceWithVAT() > 0 && paymentProxy == PaymentProxy.STRIPE) { + if(reservationCost.priceWithVAT() > 0 && paymentProxy == PaymentProxy.STRIPE) { try { transitionToInPayment(spec, principal); } catch (Exception e) { @@ -784,209 +798,61 @@ private boolean acquireGroupMembers(String reservationId, PurchaseContext purcha return true; } - public void confirmOfflinePayment(Event event, String reservationId, String username) { - TicketReservation ticketReservation = findById(reservationId).orElseThrow(IllegalArgumentException::new); - ticketReservationRepository.lockReservationForUpdate(reservationId); - Validate.isTrue(ticketReservation.getPaymentMethod() == PaymentProxy.OFFLINE, "invalid payment method"); - Validate.isTrue(ticketReservation.isPendingOfflinePayment(), "invalid status"); - - - ticketReservationRepository.confirmOfflinePayment(reservationId, TicketReservationStatus.COMPLETE.name(), event.now(clockProvider)); - - registerAlfioTransaction(event, reservationId, PaymentProxy.OFFLINE); - - auditingRepository.insert(reservationId, userRepository.findIdByUserName(username).orElse(null), event.getId(), Audit.EventType.RESERVATION_OFFLINE_PAYMENT_CONFIRMED, new Date(), Audit.EntityType.RESERVATION, ticketReservation.getId()); - - CustomerName customerName = new CustomerName(ticketReservation.getFullName(), ticketReservation.getFirstName(), ticketReservation.getLastName(), event.mustUseFirstAndLastName()); - acquireItems(PaymentProxy.OFFLINE, reservationId, ticketReservation.getEmail(), customerName, - ticketReservation.getUserLanguage(), ticketReservation.getBillingAddress(), - ticketReservation.getCustomerReference(), event, true); - - Locale language = findReservationLanguage(reservationId); - - final TicketReservation finalReservation = ticketReservationRepository.findReservationById(reservationId); - billingDocumentManager.createBillingDocument(event, finalReservation, username, orderSummaryForReservation(finalReservation, event)); - var configuration = configurationManager.getFor(EnumSet.of(DEFERRED_BANK_TRANSFER_ENABLED, DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL), ConfigurationLevel.event(event)); - if(!configuration.get(DEFERRED_BANK_TRANSFER_ENABLED).getValueAsBooleanOrDefault() || configuration.get(DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL).getValueAsBooleanOrDefault()) { - sendConfirmationEmail(event, findById(reservationId).orElseThrow(IllegalArgumentException::new), language, username); - } - extensionManager.handleReservationConfirmation(finalReservation, ticketReservationRepository.getBillingDetailsForReservation(reservationId), event); + public void confirmOfflinePayment(Event event, String reservationId, TransactionMetadataModification transactionMetadataModification, String username) { + reservationFinalizer.confirmOfflinePayment(event, reservationId, transactionMetadataModification, username); } - void registerAlfioTransaction(Event event, String reservationId, PaymentProxy paymentProxy) { - var totalPrice = totalReservationCostWithVAT(reservationId).getLeft(); - int priceWithVAT = totalPrice.getPriceWithVAT(); - long platformFee = FeeCalculator.getCalculator(event, configurationManager, requireNonNullElse(totalPrice.getCurrencyCode(), event.getCurrency())) - .apply(ticketRepository.countTicketsInReservation(reservationId), (long) priceWithVAT) - .orElse(0L); - - //FIXME we must support multiple transactions for a reservation, otherwise we can't handle properly the case of ON_SITE payments - - var transactionOptional = transactionRepository.loadOptionalByReservationId(reservationId); - String transactionId = paymentProxy.getKey() + "-" + System.currentTimeMillis(); - if(transactionOptional.isEmpty()) { - transactionRepository.insert(transactionId, null, reservationId, event.now(clockProvider), - priceWithVAT, event.getCurrency(), "Offline payment confirmed for "+reservationId, paymentProxy.getKey(), - platformFee, 0L, Transaction.Status.COMPLETE, Map.of()); - } else if(paymentProxy == PaymentProxy.OFFLINE) { - var transaction = transactionOptional.get(); - transactionRepository.update(transaction.getId(), transactionId, null, event.now(clockProvider), - platformFee, 0L, Transaction.Status.COMPLETE, Map.of()); - } else { - log.warn("ON-Site check-in: ignoring transaction registration for reservationId {}", reservationId); - } - + void registerAlfioTransactionForOnsitePayment(Event event, String reservationId) { + reservationFinalizer.registerAlfioTransaction(event, reservationId, null, PaymentProxy.ON_SITE); } public void sendConfirmationEmail(PurchaseContext purchaseContext, TicketReservation ticketReservation, Locale language, String username) { - String reservationId = ticketReservation.getId(); - - OrderSummary summary = orderSummaryForReservationId(reservationId, purchaseContext); - - List attachments; - if (configurationManager.canGenerateReceiptOrInvoiceToCustomer(purchaseContext)) { // https://github.com/alfio-event/alf.io/issues/573 - attachments = generateAttachmentForConfirmationEmail(purchaseContext, ticketReservation, language, summary, username); - } else{ - attachments = List.of(); - } - var vat = getVAT(purchaseContext); - - List configurations = new ArrayList<>(); - if(purchaseContext.ofType(PurchaseContextType.subscription)) { - var firstSubscription = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream().findFirst().orElseThrow(); - boolean sendSeparateEmailToOwner = !Objects.equals(firstSubscription.getEmail(), ticketReservation.getEmail()); - Map initialModel = Map.of( - "pin", firstSubscription.getPin(), - "subscriptionId", firstSubscription.getId(), - "includePin", true, - "fullName", firstSubscription.getFirstName() + " " + firstSubscription.getLastName()); - var model = prepareModelForReservationEmail(purchaseContext, ticketReservation, vat, summary, List.of(), initialModel); - configurations.add(new ConfirmationEmailConfiguration(TemplateResource.CONFIRMATION_EMAIL_SUBSCRIPTION, firstSubscription.getEmail(), model, sendSeparateEmailToOwner ? List.of() : attachments)); - if(sendSeparateEmailToOwner) { - var separateModel = new HashMap<>(model); - separateModel.put("includePin", false); - separateModel.put("fullName", ticketReservation.getFullName()); - configurations.add(new ConfirmationEmailConfiguration(TemplateResource.CONFIRMATION_EMAIL_SUBSCRIPTION, ticketReservation.getEmail(), separateModel, attachments)); - } - } else { - var model = prepareModelForReservationEmail(purchaseContext, ticketReservation, vat, summary, ticketRepository.findTicketsInReservation(ticketReservation.getId()), Map.of()); - configurations.add(new ConfirmationEmailConfiguration(TemplateResource.CONFIRMATION_EMAIL, ticketReservation.getEmail(), model, attachments)); - } - - var messageSource = messageSourceManager.getMessageSourceFor(purchaseContext); - var localizedType = messageSource.getMessage("purchase-context."+purchaseContext.getType(), null, language); - configurations.forEach(configuration -> { - notificationManager.sendSimpleEmail(purchaseContext, ticketReservation.getId(), configuration.getEmailAddress(), messageSource.getMessage("reservation-email-subject", - new Object[]{getShortReservationID(purchaseContext, ticketReservation), purchaseContext.getTitle().get(language.getLanguage()), localizedType}, language), - () -> templateManager.renderTemplate(purchaseContext, configuration.getTemplateResource(), configuration.getModel(), language), - configuration.getAttachments()); - }); - } - - private List generateAttachmentForConfirmationEmail(PurchaseContext purchaseContext, - TicketReservation ticketReservation, - Locale language, - OrderSummary summary, - String username) { - if(mustGenerateBillingDocument(summary, ticketReservation)) { //#459 - include PDF invoice in reservation email - BillingDocument.Type type = ticketReservation.getHasInvoiceNumber() ? INVOICE : RECEIPT; - return billingDocumentManager.generateBillingDocumentAttachment(purchaseContext, ticketReservation, language, type, username, summary); - } - return List.of(); + this.reservationHelper.sendConfirmationEmail(purchaseContext, ticketReservation, language, username); } - public void sendReservationCompleteEmailToOrganizer(PurchaseContext purchaseContext, TicketReservation ticketReservation, Locale language, String username) { - Organization organization = organizationRepository.getById(purchaseContext.getOrganizationId()); - List cc = notificationManager.getCCForEventOrganizer(purchaseContext); - - Map reservationEmailModel = prepareModelForReservationEmail(purchaseContext, ticketReservation); - - String reservationId = ticketReservation.getId(); - OrderSummary summary = orderSummaryForReservationId(reservationId, purchaseContext); - - List attachments = Collections.emptyList(); - - if (!configurationManager.canGenerateReceiptOrInvoiceToCustomer(purchaseContext) || configurationManager.isInvoiceOnly(purchaseContext)) { // https://github.com/alfio-event/alf.io/issues/573 - attachments = generateAttachmentForConfirmationEmail(purchaseContext, ticketReservation, language, summary, username); - } - - - String shortReservationID = configurationManager.getShortReservationID(purchaseContext, ticketReservation); - notificationManager.sendSimpleEmail(purchaseContext, null, organization.getEmail(), cc, "Reservation complete " + shortReservationID, - () -> templateManager.renderTemplate(purchaseContext, TemplateResource.CONFIRMATION_EMAIL_FOR_ORGANIZER, reservationEmailModel, language), - attachments); - } - - private static boolean mustGenerateBillingDocument(OrderSummary summary, TicketReservation ticketReservation) { - return !summary.getFree() && (!summary.getNotYetPaid() || (summary.getWaitingForPayment() && ticketReservation.isInvoiceRequested())); - } - - private List generateBillingDocumentAttachment(PurchaseContext purchaseContext, - TicketReservation ticketReservation, - Locale language, - Map billingDocumentModel, - BillingDocument.Type documentType) { - Map model = new HashMap<>(); - model.put(RESERVATION_ID, ticketReservation.getId()); - purchaseContext.event().ifPresent(event -> model.put("eventId", Integer.toString(event.getId()))); - model.put("language", json.asJsonString(language)); - model.put("reservationEmailModel", json.asJsonString(billingDocumentModel));//ticketReservation.getHasInvoiceNumber() - switch (documentType) { - case INVOICE: - return Collections.singletonList(new Mailer.Attachment("invoice.pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.INVOICE_PDF)); - case RECEIPT: - return Collections.singletonList(new Mailer.Attachment("receipt.pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.RECEIPT_PDF)); - case CREDIT_NOTE: - return Collections.singletonList(new Mailer.Attachment("credit-note.pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.CREDIT_NOTE_PDF)); - default: - throw new IllegalStateException(documentType+" is not supported"); - } - } private Locale findReservationLanguage(String reservationId) { - return ticketReservationRepository.findOptionalReservationById(reservationId).map(TicketReservationManager::getReservationLocale).orElse(Locale.ENGLISH); + return ticketReservationRepository.findOptionalReservationById(reservationId).map(ReservationUtil::getReservationLocale).orElse(Locale.ENGLISH); } - public void deleteOfflinePayment(Event event, String reservationId, boolean expired, boolean credit, String username) { + public void deleteOfflinePayment(Event event, String reservationId, boolean expired, boolean credit, boolean notify, String username) { TicketReservation reservation = findById(reservationId).orElseThrow(IllegalArgumentException::new); Validate.isTrue(reservation.getStatus() == OFFLINE_PAYMENT || reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT, "Invalid reservation status"); Validate.isTrue(!(credit && reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT), "Cannot credit deferred payment"); if(credit) { - creditReservation(reservation, username); + creditReservation(reservation, username, notify); } else { - Map emailModel = prepareModelForReservationEmail(event, reservation); - Locale reservationLanguage = findReservationLanguage(reservationId); - String subject = getReservationEmailSubject(event, reservationLanguage, "reservation-email-expired-subject", reservation.getId()); - notificationManager.sendSimpleEmail(event, reservationId, reservation.getEmail(), subject, - () -> templateManager.renderTemplate(event, TemplateResource.OFFLINE_RESERVATION_EXPIRED_EMAIL, emailModel, reservationLanguage) - ); + if (notify) { + Map emailModel = reservationHelper.prepareModelForReservationEmail(event, reservation); + Locale reservationLanguage = findReservationLanguage(reservationId); + String subject = reservationHelper.getReservationEmailSubject(event, reservationLanguage, "reservation-email-expired-subject", reservation.getId()); + notificationManager.sendSimpleEmail(event, reservationId, reservation.getEmail(), subject, + () -> templateManager.renderTemplate(event, TemplateResource.OFFLINE_RESERVATION_EXPIRED_EMAIL, emailModel, reservationLanguage) + ); + } cancelReservation(reservation, expired, username); } } - private String getReservationEmailSubject(PurchaseContext purchaseContext, Locale reservationLanguage, String key, String id) { - return messageSourceManager.getMessageSourceFor(purchaseContext) - .getMessage(key, new Object[]{id, purchaseContext.getDisplayName()}, reservationLanguage); - } - @Transactional public void issueCreditNoteForReservation(PurchaseContext purchaseContext, TicketReservation reservation, String username, boolean sendEmail) { var reservationId = reservation.getId(); ticketReservationRepository.updateReservationStatus(reservationId, TicketReservationStatus.CREDIT_NOTE_ISSUED.toString()); auditingRepository.insert(reservationId, userRepository.nullSafeFindIdByUserName(username).orElse(null), purchaseContext, Audit.EventType.CREDIT_NOTE_ISSUED, new Date(), RESERVATION, reservationId); - var model = prepareModelForReservationEmail(purchaseContext, reservation, getVAT(purchaseContext), orderSummaryForReservation(reservation, purchaseContext), ticketRepository.findTicketsInReservation(reservation.getId()), Map.of()); + var model = prepareModelForReservationEmail(purchaseContext, reservation, reservationHelper.getVAT(purchaseContext), orderSummaryForReservation(reservation, purchaseContext), ticketRepository.findTicketsInReservation(reservation.getId()), Map.of()); BillingDocument billingDocument = billingDocumentManager.createBillingDocument(purchaseContext, reservation, username, BillingDocument.Type.CREDIT_NOTE, orderSummaryForReservation(reservation, purchaseContext)); var organization = organizationRepository.getById(purchaseContext.getOrganizationId()); extensionManager.handleCreditNoteGenerated(reservation, purchaseContext, ((OrderSummary) model.get("orderSummary")).getOriginalTotalPrice(), billingDocument.getId(), Map.of(ORGANIZATION, organization)); if(sendEmail) { + var reservationLocale = getReservationLocale(reservation); notificationManager.sendSimpleEmail(purchaseContext, reservationId, reservation.getEmail(), - getReservationEmailSubject(purchaseContext, getReservationLocale(reservation), "credit-note-issued-email-subject", reservation.getId()), - () -> templateManager.renderTemplate(purchaseContext, TemplateResource.CREDIT_NOTE_ISSUED_EMAIL, model, getReservationLocale(reservation)), - generateBillingDocumentAttachment(purchaseContext, reservation, getReservationLocale(reservation), billingDocument.getModel(), CREDIT_NOTE) + reservationHelper.getReservationEmailSubject(purchaseContext, reservationLocale, "credit-note-issued-email-subject", reservation.getId()), + () -> templateManager.renderTemplate(purchaseContext, TemplateResource.CREDIT_NOTE_ISSUED_EMAIL, model, reservationLocale), + reservationHelper.generateBillingDocumentAttachment(purchaseContext, reservation, reservationLocale, billingDocument.getModel(), CREDIT_NOTE) ); } } @@ -1014,7 +880,7 @@ void issueCreditNoteForRefund(PurchaseContext purchaseContext, TicketReservation var cost = new TotalPrice(priceContainer.getSrcPriceCts(), unitToCents(priceContainer.getVAT(), currencyCode), 0, 0, currencyCode); var orderSummary = new OrderSummary( cost, - List.of(new SummaryRow(summaryRowTitle, formattedAmount, formattedPriceBeforeVat, 1, formattedAmount, formattedPriceBeforeVat, unitToCents(refundAmount, currencyCode), SummaryType.TICKET, null)), + List.of(new SummaryRow(summaryRowTitle, formattedAmount, formattedPriceBeforeVat, 1, formattedAmount, formattedPriceBeforeVat, unitToCents(refundAmount, currencyCode), SummaryType.TICKET, null, priceContainer.getVatStatus())), false, formattedAmount, formatUnit(priceContainer.getVAT(), currencyCode), @@ -1038,83 +904,16 @@ public Map prepareModelForReservationEmail(PurchaseContext purch OrderSummary summary, List ticketsToInclude, Map initialOptions) { - Organization organization = organizationRepository.getById(purchaseContext.getOrganizationId()); - String baseUrl = configurationManager.baseUrl(purchaseContext); - var reservationId = reservation.getId(); - String reservationUrl = reservationUrl(reservationId); - String reservationShortID = getShortReservationID(purchaseContext, reservation); - - var bankingInfo = configurationManager.getFor(Set.of(INVOICE_ADDRESS, BANK_ACCOUNT_NR, BANK_ACCOUNT_OWNER), ConfigurationLevel.purchaseContext(purchaseContext)); - Optional invoiceAddress = bankingInfo.get(INVOICE_ADDRESS).getValue(); - Optional bankAccountNr = bankingInfo.get(BANK_ACCOUNT_NR).getValue(); - Optional bankAccountOwner = bankingInfo.get(BANK_ACCOUNT_OWNER).getValue(); - - Map> ticketsByCategory = ticketsToInclude - .stream() - .collect(groupingBy(Ticket::getCategoryId)); - final List ticketsWithCategory; - if(!ticketsByCategory.isEmpty()) { - ticketsWithCategory = ticketCategoryRepository.findByIds(ticketsByCategory.keySet()) - .stream() - .flatMap(tc -> ticketsByCategory.get(tc.getId()).stream().map(t -> new TicketWithCategory(t, tc))) - .collect(toList()); - } else { - ticketsWithCategory = Collections.emptyList(); - } - Map baseModel = new HashMap<>(); - baseModel.putAll(initialOptions); - baseModel.putAll(extensionManager.handleReservationEmailCustomText(purchaseContext, reservation, ticketReservationRepository.getAdditionalInfo(reservationId)) - .map(CustomEmailText::toMap) - .orElse(Map.of())); - Map model = TemplateResource.prepareModelForConfirmationEmail(organization, purchaseContext, reservation, vat, ticketsWithCategory, summary, baseUrl, reservationUrl, reservationShortID, invoiceAddress, bankAccountNr, bankAccountOwner, baseModel); - boolean euBusiness = StringUtils.isNotBlank(reservation.getVatCountryCode()) && StringUtils.isNotBlank(reservation.getVatNr()) - && configurationManager.getForSystem(ConfigurationKeys.EU_COUNTRIES_LIST).getRequiredValue().contains(reservation.getVatCountryCode()) - && VatStatus.isVatExempt(reservation.getVatStatus()); - model.put("euBusiness", euBusiness); - model.put("publicId", configurationManager.getPublicReservationID(purchaseContext, reservation)); - model.put("invoicingAdditionalInfo", loadAdditionalInfo(reservationId).getInvoicingAdditionalInfo()); - if(purchaseContext.getType() == PurchaseContextType.event) { - var event = purchaseContext.event().orElseThrow(); - model.put("displayLocation", ticketsWithCategory.stream() - .noneMatch(tc -> EventUtil.isAccessOnline(tc.getCategory(), event))); - } else { - model.put("displayLocation", false); - } - if(ticketReservationRepository.hasSubscriptionApplied(reservationId)) { - model.put("displaySubscriptionUsage", true); - var subscription = subscriptionRepository.findAppliedSubscriptionByReservationId(reservationId).orElseThrow(); - if(subscription.getMaxEntries() > -1) { - var subscriptionUsageDetails = UsageDetails.fromSubscription(subscription, ticketRepository.countSubscriptionUsage(subscription.getId(), null)); - model.put("subscriptionUsageDetails", subscriptionUsageDetails); - model.put("subscriptionUrl", reservationUrl(subscription.getReservationId())); - } - } - return model; - } - - @Transactional(readOnly = true) - public Map prepareModelForReservationEmail(Event event, TicketReservation reservation, Optional vat, OrderSummary summary) { - - var initialOptions = extensionManager.handleReservationEmailCustomText(event, reservation, ticketReservationRepository.getAdditionalInfo(reservation.getId())) - .map(CustomEmailText::toMap) - .orElse(Map.of()); - return prepareModelForReservationEmail(event, reservation, vat, summary, ticketRepository.findTicketsInReservation(reservation.getId()), initialOptions); + return reservationHelper.prepareModelForReservationEmail(purchaseContext, reservation, vat, summary, ticketsToInclude, initialOptions); } public TicketReservationAdditionalInfo loadAdditionalInfo(String reservationId) { return ticketReservationRepository.getAdditionalInfo(reservationId); } - @Transactional(readOnly = true) - public Map prepareModelForReservationEmail(PurchaseContext purchaseContext, TicketReservation reservation) { - Optional vat = getVAT(purchaseContext); - OrderSummary summary = orderSummaryForReservationId(reservation.getId(), purchaseContext); - return prepareModelForReservationEmail(purchaseContext, reservation, vat, summary, ticketRepository.findTicketsInReservation(reservation.getId()), Map.of()); - } - private Map prepareModelForPartialCreditNote(Event event, TicketReservation reservation, List removedTickets) { - var orderSummary = orderSummaryForCreditNote(reservation, event, removedTickets); - var optionalVat = getVAT(event); + var orderSummary = orderSummaryGenerator.orderSummaryForCreditNote(reservation, event, removedTickets); + var optionalVat = reservationHelper.getVAT(event); return prepareModelForReservationEmail(event, reservation, optionalVat, orderSummary, removedTickets, Map.of()); } @@ -1124,7 +923,7 @@ private void transitionToInPayment(PaymentSpecification spec, Principal principa if(optionalStatusAndValidation.isPresent() && optionalStatusAndValidation.get().getStatus() == COMPLETE) { // reservation has been already completed. Let's check if there is a corresponding audit event Validate.isTrue(auditingRepository.countAuditsOfTypeForReservation(spec.getReservationId(), PAYMENT_CONFIRMED) == 1, "Trying to confirm an already paid reservation, but can't find autiting event"); - } else { + } else if(optionalStatusAndValidation.isPresent() && optionalStatusAndValidation.get().getStatus() == PENDING) { int updatedReservation = ticketReservationRepository.updateTicketReservation(spec.getReservationId(), IN_PAYMENT.toString(), spec.getEmail(), spec.getCustomerName().getFullName(), spec.getCustomerName().getFirstName(), spec.getCustomerName().getLastName(), @@ -1184,208 +983,30 @@ public Optional> from(String eventName, } /** - * Set the tickets attached to the reservation to the ACQUIRED state and the ticket reservation to the COMPLETE state. Additionally it will save email/fullName/billingaddress/userLanguage. + * Set the tickets attached to the reservation to the ACQUIRED state and the ticket reservation to the COMPLETE state. + * Additionally, it will save email/fullName/billingAddress/userLanguage. */ void completeReservation(PaymentSpecification spec, PaymentProxy paymentProxy, boolean sendReservationConfirmationEmail, boolean sendTickets, String username) { - String reservationId = spec.getReservationId(); - var purchaseContext = spec.getPurchaseContext(); - final TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId); - // retrieve reservation owner if username is null - Integer userId; - if(username != null) { - userId = userRepository.getByUsername(username).getId(); - } else { - userId = ticketReservationRepository.getReservationOwnerAndOrganizationId(reservationId) - .map(UserIdAndOrganizationId::getUserId) - .orElse(null); + // pre-acquire special price tokens before committing, in order to ensure atomicity + reservationFinalizer.acquireSpecialPriceTokens(spec.getReservationId()); + // update reservation status to mark the finalization, but first retrieve the current one + // set by the payment provider. This is useful especially in case a single "PaymentProxy" can produce different statuses + // like OFFLINE_PAYMENT and DEFERRED_OFFLINE_PAYMENT + var currentStatus = ticketReservationRepository.findOptionalStatusAndValidationById(spec.getReservationId()).orElseThrow().getStatus(); + TicketReservationStatus targetStatus = FINALIZING; + if (currentStatus == OFFLINE_PAYMENT || currentStatus == DEFERRED_OFFLINE_PAYMENT) { + targetStatus = OFFLINE_FINALIZING; } - Locale locale = LocaleUtil.forLanguageTag(reservation.getUserLanguage()); - List tickets = null; - if(paymentProxy != PaymentProxy.OFFLINE) { - tickets = acquireItems(paymentProxy, reservationId, spec.getEmail(), spec.getCustomerName(), spec.getLocale().getLanguage(), spec.getBillingAddress(), spec.getCustomerReference(), spec.getPurchaseContext(), sendTickets); - extensionManager.handleReservationConfirmation(reservation, ticketReservationRepository.getBillingDetailsForReservation(reservationId), spec.getPurchaseContext()); - } - - Date eventTime = new Date(); - auditingRepository.insert(reservationId, userId, purchaseContext, Audit.EventType.RESERVATION_COMPLETE, eventTime, Audit.EntityType.RESERVATION, reservationId); - ticketReservationRepository.updateRegistrationTimestamp(reservationId, ZonedDateTime.now(clockProvider.withZone(spec.getPurchaseContext().getZoneId()))); - if(spec.isTcAccepted()) { - auditingRepository.insert(reservationId, userId, purchaseContext, Audit.EventType.TERMS_CONDITION_ACCEPTED, eventTime, Audit.EntityType.RESERVATION, reservationId, singletonList(singletonMap("termsAndConditionsUrl", spec.getPurchaseContext().getTermsAndConditionsUrl()))); - } - - if(eventHasPrivacyPolicy(spec.getPurchaseContext()) && spec.isPrivacyAccepted()) { - auditingRepository.insert(reservationId, userId, purchaseContext, Audit.EventType.PRIVACY_POLICY_ACCEPTED, eventTime, Audit.EntityType.RESERVATION, reservationId, singletonList(singletonMap("privacyPolicyUrl", spec.getPurchaseContext().getPrivacyPolicyUrl()))); - } - - if(sendReservationConfirmationEmail) { - TicketReservation updatedReservation = ticketReservationRepository.findReservationById(reservationId); - sendConfirmationEmailIfNecessary(updatedReservation, tickets, purchaseContext, locale, username); - sendReservationCompleteEmailToOrganizer(spec.getPurchaseContext(), updatedReservation, locale, username); - } - } - - void sendConfirmationEmailIfNecessary(TicketReservation ticketReservation, - List tickets, - PurchaseContext purchaseContext, - Locale locale, - String username) { - if(purchaseContext.ofType(PurchaseContextType.event)) { - var config = configurationManager.getFor(List.of(SEND_RESERVATION_EMAIL_IF_NECESSARY, SEND_TICKETS_AUTOMATICALLY), purchaseContext.getConfigurationLevel()); - if(ticketReservation.getSrcPriceCts() > 0 - || CollectionUtils.isEmpty(tickets) || tickets.size() > 1 - || !tickets.get(0).getEmail().equals(ticketReservation.getEmail()) - || !config.get(SEND_RESERVATION_EMAIL_IF_NECESSARY).getValueAsBooleanOrDefault() - || !config.get(SEND_TICKETS_AUTOMATICALLY).getValueAsBooleanOrDefault() - ) { - sendConfirmationEmail(purchaseContext, ticketReservation, locale, username); - } - } else { - sendConfirmationEmail(purchaseContext, ticketReservation, locale, username); - } - } - - private boolean eventHasPrivacyPolicy(PurchaseContext event) { - return StringUtils.isNotBlank(event.getPrivacyPolicyLinkOrNull()); - } - - private List acquireItems(PaymentProxy paymentProxy, String reservationId, String email, CustomerName customerName, - String userLanguage, String billingAddress, String customerReference, PurchaseContext purchaseContext, boolean sendTickets) { - switch (purchaseContext.getType()) { - case event: { - acquireEventTickets(paymentProxy, reservationId, purchaseContext, purchaseContext.event().orElseThrow()); - break; - } - case subscription: { - acquireSubscription(paymentProxy, reservationId, purchaseContext, customerName, email); - break; - } - default: throw new IllegalStateException("not supported purchase context"); - } - - specialPriceRepository.updateStatusForReservation(singletonList(reservationId), Status.TAKEN.toString()); - ZonedDateTime timestamp = ZonedDateTime.now(clockProvider.getClock()); - int updatedReservation = ticketReservationRepository.updateTicketReservation(reservationId, TicketReservationStatus.COMPLETE.toString(), email, - customerName.getFullName(), customerName.getFirstName(), customerName.getLastName(), userLanguage, billingAddress, timestamp, paymentProxy.toString(), customerReference); - - - Validate.isTrue(updatedReservation == 1, "expected exactly one updated reservation, got " + updatedReservation); - - waitingQueueManager.fireReservationConfirmed(reservationId); - //we must notify the plugins about ticket assignment and send them by email - TicketReservation reservation = findById(reservationId).orElseThrow(IllegalStateException::new); - List assignedTickets = findTicketsInReservation(reservationId); - assignedTickets.stream() - .filter(ticket -> StringUtils.isNotBlank(ticket.getFullName()) || StringUtils.isNotBlank(ticket.getFirstName()) || StringUtils.isNotBlank(ticket.getEmail())) - .forEach(ticket -> { - var event = purchaseContext.event().orElseThrow(); - Locale locale = LocaleUtil.forLanguageTag(ticket.getUserLanguage()); - var additionalInfo = retrieveAttendeeAdditionalInfoForTicket(ticket); - if((paymentProxy != PaymentProxy.ADMIN || sendTickets) && configurationManager.getFor(SEND_TICKETS_AUTOMATICALLY, ConfigurationLevel.event(event)).getValueAsBooleanOrDefault()) { - sendTicketByEmail(ticket, locale, event, getTicketEmailGenerator(event, reservation, locale, additionalInfo)); - } - extensionManager.handleTicketAssignment(ticket, ticketCategoryRepository.getById(ticket.getCategoryId()), additionalInfo); - }); - return assignedTickets; - } - - private void acquireSubscription(PaymentProxy paymentProxy, String reservationId, PurchaseContext purchaseContext, CustomerName customerName, String email) { - var status = paymentProxy.isDeskPaymentRequired() ? AllocationStatus.TO_BE_PAID : AllocationStatus.ACQUIRED; - var subscriptionDescriptor = (SubscriptionDescriptor) purchaseContext; - ZonedDateTime validityFrom = null; - ZonedDateTime validityTo = null; - var confirmationTimestamp = subscriptionDescriptor.now(clockProvider); - if(subscriptionDescriptor.getValidityFrom() != null) { - validityFrom = subscriptionDescriptor.getValidityFrom(); - validityTo = subscriptionDescriptor.getValidityTo(); - } else if(subscriptionDescriptor.getValidityUnits() != null) { - validityFrom = confirmationTimestamp; - var temporalUnit = requireNonNullElse(subscriptionDescriptor.getValidityTimeUnit(), SubscriptionTimeUnit.DAYS).getTemporalUnit(); - validityTo = confirmationTimestamp.plus(subscriptionDescriptor.getValidityUnits(), temporalUnit) - .with(ChronoField.HOUR_OF_DAY, 23) - .with(ChronoField.MINUTE_OF_HOUR, 59) - .with(ChronoField.SECOND_OF_MINUTE, 59); - } - var subscription = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream().findFirst().orElseThrow(); - var updatedSubscriptions = subscriptionRepository.confirmSubscription(reservationId, - status, - requireNonNullElse(subscription.getFirstName(), customerName.getFirstName()), - requireNonNullElse(subscription.getLastName(), customerName.getLastName()), - requireNonNullElse(subscription.getEmail(), email), - subscriptionDescriptor.getMaxEntries(), - validityFrom, - validityTo, - confirmationTimestamp, - subscriptionDescriptor.getTimeZone()); - subscriptionRepository.findSubscriptionsByReservationId(reservationId) // at the moment it's safe because there can be only one subscription per reservation - .forEach(subscriptionId -> auditingRepository.insert(reservationId, null, purchaseContext, SUBSCRIPTION_ACQUIRED, new Date(), Audit.EntityType.SUBSCRIPTION, subscriptionId.toString())); - Validate.isTrue(updatedSubscriptions > 0, "must have updated at least one subscription"); - } - - private void acquireEventTickets(PaymentProxy paymentProxy, String reservationId, PurchaseContext purchaseContext, Event event) { - TicketStatus ticketStatus = paymentProxy.isDeskPaymentRequired() ? TicketStatus.TO_BE_PAID : TicketStatus.ACQUIRED; - AdditionalServiceItemStatus asStatus = paymentProxy.isDeskPaymentRequired() ? AdditionalServiceItemStatus.TO_BE_PAID : AdditionalServiceItemStatus.ACQUIRED; - Map preUpdateTicket = ticketRepository.findTicketsInReservation(reservationId).stream().collect(toMap(Ticket::getId, Function.identity())); - int updatedTickets = ticketRepository.updateTicketsStatusWithReservationId(reservationId, ticketStatus.toString()); - if(!configurationManager.getFor(ENABLE_TICKET_TRANSFER, purchaseContext.getConfigurationLevel()).getValueAsBooleanOrDefault()) { - //automatically lock assignment - int locked = ticketRepository.forbidReassignment(preUpdateTicket.keySet()); - Validate.isTrue(updatedTickets == locked, "Expected to lock "+updatedTickets+" tickets, locked "+ locked); - Map postUpdateTicket = ticketRepository.findTicketsInReservation(reservationId).stream().collect(toMap(Ticket::getId, Function.identity())); - - postUpdateTicket.forEach( - (id, ticket) -> auditUpdateTicket(preUpdateTicket.get(id), Collections.emptyMap(), ticket, Collections.emptyMap(), event.getId())); - } - var ticketsWithMetadataById = ticketRepository.findTicketsInReservationWithMetadata(reservationId) - .stream().collect(toMap(twm -> twm.getTicket().getId(), Function.identity())); - ticketsWithMetadataById.forEach((id, ticketWithMetadata) -> { - var newMetadataOptional = extensionManager.handleTicketAssignmentMetadata(ticketWithMetadata, event); - newMetadataOptional.ifPresent(metadata -> { - var existingContainer = TicketMetadataContainer.copyOf(ticketWithMetadata.getMetadata()); - var general = new HashMap<>(existingContainer.getMetadataForKey(TicketMetadataContainer.GENERAL) - .orElseGet(TicketMetadata::empty).getAttributes()); - general.putAll(metadata.getAttributes()); - existingContainer.putMetadata(TicketMetadataContainer.GENERAL, new TicketMetadata(null, null, general)); - ticketRepository.updateTicketMetadata(id, existingContainer); - auditUpdateMetadata(reservationId, id, event.getId(), existingContainer, ticketWithMetadata.getMetadata()); - }); - auditUpdateTicket(preUpdateTicket.get(id), Collections.emptyMap(), ticketWithMetadata.getTicket(), Collections.emptyMap(), event.getId()); - }); - int updatedAS = additionalServiceItemRepository.updateItemsStatusWithReservationUUID(reservationId, asStatus); - Validate.isTrue(updatedTickets + updatedAS > 0, "no items have been updated"); + ticketReservationRepository.updateReservationStatus(spec.getReservationId(), targetStatus.name()); + // run detached reservation confirmation + this.applicationEventPublisher.publishEvent(new FinalizeReservation(spec, paymentProxy, sendReservationConfirmationEmail, sendTickets, username, currentStatus)); } public PartialTicketTextGenerator getTicketEmailGenerator(Event event, TicketReservation ticketReservation, Locale ticketLanguage, Map> additionalInfo) { - return ticket -> { - Organization organization = organizationRepository.getById(event.getOrganizationId()); - String ticketUrl = ticketUpdateUrl(event, ticket.getUuid()); - var ticketCategory = ticketCategoryRepository.getById(ticket.getCategoryId()); - - var initialModel = new HashMap<>(extensionManager.handleTicketEmailCustomText(event, ticketReservation, ticketReservationRepository.getAdditionalInfo(ticketReservation.getId()), ticketFieldRepository.findAllByTicketId(ticket.getId())) - .map(CustomEmailText::toMap) - .orElse(Map.of())); - if(EventUtil.isAccessOnline(ticketCategory, event)) { - initialModel.putAll(TicketCheckInUtil.getOnlineCheckInInfo( - extensionManager, - eventRepository, - ticketCategoryRepository, - configurationManager, - event, - ticketLanguage, - ticket, - ticketCategory, - additionalInfo - )); - } - var baseUrl = StringUtils.removeEnd(configurationManager.getFor(BASE_URL, ConfigurationLevel.event(event)).getRequiredValue(), "/"); - var calendarUrl = UriComponentsBuilder.fromUriString(baseUrl + "/api/v2/public/event/{eventShortName}/calendar/{currentLang}") - .queryParam("type", "google") - .build(Map.of("eventShortName", event.getShortName(), "currentLang", ticketLanguage.getLanguage())) - .toString(); - return TemplateProcessor.buildPartialEmail(event, organization, ticketReservation, ticketCategory, templateManager, baseUrl, ticketUrl, calendarUrl, ticketLanguage, initialModel).generate(ticket); - }; + return reservationHelper.getTicketEmailGenerator(event, ticketReservation, ticketLanguage, additionalInfo); } @Transactional @@ -1427,7 +1048,7 @@ public void cleanupExpiredReservations(Date expirationDate) { var toDelete = expiredReservationIds.stream() .filter(id -> !reservationsToIgnore.contains(id)) - .collect(toList()); + .toList(); subscriptionRepository.deleteSubscriptionWithReservationId(toDelete); specialPriceRepository.resetToFreeAndCleanupForReservation(toDelete); @@ -1443,7 +1064,7 @@ public void cleanupExpiredReservations(Date expirationDate) { .collect(Collectors.groupingBy(ReservationIdAndEventId::getEventId)); reservationIdsByEvent.forEach((eventId, reservations) -> { Event event = eventRepository.findById(eventId); - List reservationIds = reservations.stream().map(ReservationIdAndEventId::getId).collect(toList()); + List reservationIds = reservations.stream().map(ReservationIdAndEventId::getId).toList(); extensionManager.handleReservationsExpiredForEvent(event, reservationIds); billingDocumentRepository.deleteForReservations(reservationIds, eventId); transactionRepository.deleteForReservations(reservationIds); @@ -1463,7 +1084,7 @@ private void cleanupOfflinePayment(String reservationId) { Event event = eventRepository.findByReservationId(reservationId); boolean enabled = configurationManager.getFor(AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT, ConfigurationLevel.event(event)).getValueAsBooleanOrDefault(); if (enabled) { - deleteOfflinePayment(event, reservationId, true, false, null); + deleteOfflinePayment(event, reservationId, true, false, true, null); } else { log.trace("Will not cleanup reservation with id {} because the automatic removal has been disabled", reservationId); } @@ -1483,7 +1104,7 @@ private void cleanupOfflinePayment(String reservationId) { public void markExpiredInPaymentReservationAsStuck(Date expirationDate) { List> stuckReservations = findStuckPaymentsToBeNotified(expirationDate); if(!stuckReservations.isEmpty()) { - List ids = stuckReservations.stream().map(p -> p.getLeft().getId()).collect(toList()); + List ids = stuckReservations.stream().map(p -> p.getLeft().getId()).toList(); ticketReservationRepository.updateReservationsStatus(ids, TicketReservationStatus.STUCK.name()); @@ -1496,7 +1117,7 @@ public void markExpiredInPaymentReservationAsStuck(Date expirationDate) { notificationManager.sendSimpleEmail(event, null, organization.getEmail(), STUCK_TICKETS_SUBJECT, () -> RenderedTemplate.plaintext(String.format(STUCK_TICKETS_MSG, event.getDisplayName()), Map.of())); - extensionManager.handleStuckReservations(event, reservations.stream().map(p -> p.getLeft().getId()).collect(toList())); + extensionManager.handleStuckReservations(event, reservations.stream().map(p -> p.getLeft().getId()).toList()); }); } } @@ -1532,35 +1153,7 @@ private List> findStuckPaymentsToBeNotified(Date handlePaymentWebhookResult(event, providerAndWebhookResult.getLeft(), paymentWebhookResult, reservation, transaction, paymentContext, "stuck-check", false); return paymentWebhookResult.getType() == PaymentWebhookResult.Type.NOT_RELEVANT; }) - .collect(toList()); - } - - private static Pair> totalReservationCostWithVAT(PromoCodeDiscount promoCodeDiscount, - PurchaseContext purchaseContext, - TicketReservation reservation, - List tickets, - List>> additionalServiceItems, - List subscriptions, - Optional appliedSubscription) { - - String currencyCode = purchaseContext.getCurrency(); - List ticketPrices = tickets.stream().map(t -> TicketPriceContainer.from(t, reservation.getVatStatus(), purchaseContext.getVat(), purchaseContext.getVatStatus(), promoCodeDiscount)).collect(toList()); - int discountedTickets = (int) ticketPrices.stream().filter(t -> t.getAppliedDiscount().compareTo(BigDecimal.ZERO) > 0).count(); - int discountAppliedCount = discountedTickets <= 1 || promoCodeDiscount.getDiscountType() == DiscountType.FIXED_AMOUNT ? discountedTickets : 1; - if(discountAppliedCount == 0 && promoCodeDiscount != null && promoCodeDiscount.getDiscountType() == DiscountType.FIXED_AMOUNT_RESERVATION) { - discountAppliedCount = 1; - } - var reservationPriceCalculator = ReservationPriceCalculator.from(reservation, promoCodeDiscount, tickets, purchaseContext, additionalServiceItems, subscriptions, appliedSubscription); - var price = new TotalPrice(unitToCents(reservationPriceCalculator.getFinalPrice(), currencyCode), - unitToCents(reservationPriceCalculator.getVAT(), currencyCode), - -MonetaryUtil.unitToCents(reservationPriceCalculator.getAppliedDiscount(), currencyCode), - discountAppliedCount, - currencyCode); - return Pair.of(price, Optional.ofNullable(promoCodeDiscount)); - } - - private static Function>, Stream> generateASIPriceContainers(PurchaseContext purchaseContext, PromoCodeDiscount discount) { - return p -> p.getValue().stream().map(asi -> AdditionalServiceItemPriceContainer.from(asi, p.getKey(), purchaseContext, discount)); + .toList(); } /** @@ -1570,260 +1163,19 @@ private static Function>, St * @return */ public Pair> totalReservationCostWithVAT(String reservationId) { - return totalReservationCostWithVAT(ticketReservationRepository.findReservationById(reservationId)); + return reservationCostCalculator.totalReservationCostWithVAT(reservationId); } public Pair> totalReservationCostWithVAT(TicketReservation reservation) { - return totalReservationCostWithVAT(purchaseContextManager.findByReservationId(reservation.getId()).orElseThrow(), reservation, ticketRepository.findTicketsInReservation(reservation.getId())); - } - - private Pair> totalReservationCostWithVAT(PurchaseContext purchaseContext, TicketReservation reservation, List tickets) { - var promoCodeDiscount = Optional.ofNullable(reservation.getPromoCodeDiscountId()).map(promoCodeDiscountRepository::findById); - var subscriptions = subscriptionRepository.findSubscriptionsByReservationId(reservation.getId()); - var appliedSubscription = subscriptionRepository.findAppliedSubscriptionByReservationId(reservation.getId()); - return totalReservationCostWithVAT(promoCodeDiscount.orElse(null), purchaseContext, reservation, tickets, - purchaseContext.event().map(event -> collectAdditionalServiceItems(reservation.getId(), event)).orElse(List.of()), - subscriptions, - appliedSubscription); - } - - private String formatPromoCode(PromoCodeDiscount promoCodeDiscount, List tickets, Locale locale, PurchaseContext purchaseContext) { - - if(promoCodeDiscount.getCodeType() == CodeType.DYNAMIC) { - return messageSourceManager.getMessageSourceFor(purchaseContext).getMessage("reservation.dynamic.discount.description", null, locale); //we don't expose the internal promo code - } - - List filteredTickets = tickets.stream().filter(ticket -> promoCodeDiscount.getCategories().contains(ticket.getCategoryId())).collect(toList()); - - if (promoCodeDiscount.getCategories().isEmpty() || filteredTickets.isEmpty()) { - return promoCodeDiscount.getPromoCode(); - } - - String formattedDiscountedCategories = filteredTickets.stream() - .map(Ticket::getCategoryId) - .collect(toSet()) - .stream() - .map(categoryId -> ticketCategoryRepository.getByIdAndActive(categoryId, promoCodeDiscount.getEventId()).getName()) - .collect(Collectors.joining(", ", "(", ")")); - - - return promoCodeDiscount.getPromoCode() + " " + formattedDiscountedCategories; + return reservationCostCalculator.totalReservationCostWithVAT(reservation); } public OrderSummary orderSummaryForReservationId(String reservationId, PurchaseContext purchaseContext) { - TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId); - return orderSummaryForReservation(reservation, purchaseContext); + return orderSummaryGenerator.orderSummaryForReservationId(reservationId, purchaseContext); } public OrderSummary orderSummaryForReservation(TicketReservation reservation, PurchaseContext context) { - var totalPriceAndDiscount = totalReservationCostWithVAT(reservation); - TotalPrice reservationCost = totalPriceAndDiscount.getLeft(); - PromoCodeDiscount discount = totalPriceAndDiscount.getRight().orElse(null); - // - boolean free = reservationCost.getPriceWithVAT() == 0; - String refundedAmount = null; - - boolean hasRefund = auditingRepository.countAuditsOfTypeForReservation(reservation.getId(), Audit.EventType.REFUND) > 0; - - if(hasRefund) { - refundedAmount = paymentManager.getInfo(reservation, context).getPaymentInformation().getRefundedAmount(); - } - - var currencyCode = reservation.getCurrencyCode(); - return new OrderSummary(reservationCost, - extractSummary(reservation.getId(), reservation.getVatStatus(), context, LocaleUtil.forLanguageTag(reservation.getUserLanguage()), discount, reservationCost), - free, - formatCents(reservationCost.getPriceWithVAT(), currencyCode), - formatCents(reservationCost.getVAT(), currencyCode), - reservation.getStatus() == TicketReservationStatus.OFFLINE_PAYMENT, - reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT, - reservation.getPaymentMethod() == PaymentProxy.ON_SITE, - Optional.ofNullable(context.getVat()).map(p -> MonetaryUtil.formatCents(MonetaryUtil.unitToCents(p, currencyCode), currencyCode)).orElse(null), - reservation.getVatStatus(), - refundedAmount); - } - - private OrderSummary orderSummaryForCreditNote(TicketReservation reservation, PurchaseContext purchaseContext, List removedTickets) { - var totalPriceAndDiscount = totalReservationCostWithVAT(null, purchaseContext, reservation, removedTickets, List.of(), List.of(), Optional.empty()); - TotalPrice reservationCost = totalPriceAndDiscount.getLeft(); - // - boolean free = reservationCost.getPriceWithVAT() == 0; - - var currencyCode = reservation.getCurrencyCode(); - return new OrderSummary(reservationCost, - extractSummary(reservation.getVatStatus(), purchaseContext, LocaleUtil.forLanguageTag(reservation.getUserLanguage()), null, reservationCost, removedTickets, Stream.empty(), subscriptionRepository.findSubscriptionsByReservationId(reservation.getId())), - free, - formatCents(reservationCost.getPriceWithVAT(), currencyCode), - formatCents(reservationCost.getVAT(), currencyCode), - reservation.getStatus() == TicketReservationStatus.OFFLINE_PAYMENT, - reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT, - reservation.getPaymentMethod() == PaymentProxy.ON_SITE, - Optional.ofNullable(purchaseContext.getVat()).map(p -> MonetaryUtil.formatCents(MonetaryUtil.unitToCents(p, currencyCode), currencyCode)).orElse(null), - reservation.getVatStatus(), - null); - } - - List extractSummary(VatStatus reservationVatStatus, - PurchaseContext purchaseContext, - Locale locale, - PromoCodeDiscount promoCodeDiscount, - TotalPrice reservationCost, - List ticketsToInclude, - Stream>> additionalServicesToInclude, - List subscriptionsToInclude) { - log.trace("extract summary subscriptionsToInclude {}", subscriptionsToInclude); - List summary = new ArrayList<>(); - var currencyCode = reservationCost.getCurrencyCode(); - List tickets = ticketsToInclude.stream() - .map(t -> TicketPriceContainer.from(t, reservationVatStatus, purchaseContext.getVat(), purchaseContext.getVatStatus(), promoCodeDiscount)).collect(toList()); - purchaseContext.event().ifPresent(event -> { - boolean multipleTaxRates = tickets.stream().map(TicketPriceContainer::getVatStatus).collect(Collectors.toSet()).size() > 1; - var ticketsByCategory = tickets.stream() - .collect(Collectors.groupingBy(TicketPriceContainer::getCategoryId)); - List>> sorted; - if (multipleTaxRates) { - sorted = ticketsByCategory - .entrySet() - .stream() - .sorted(Comparator.comparing((Entry> e) -> e.getValue().get(0).getVatStatus()).reversed()) - .collect(Collectors.toList()); - } else { - sorted = new ArrayList<>(ticketsByCategory.entrySet()); - } - Map categoriesById; - - if(ticketsByCategory.isEmpty()) { - categoriesById = Map.of(); - } else { - categoriesById = ticketCategoryRepository.getByIdsAndActive(ticketsByCategory.keySet(), event.getId()) - .stream() - .collect(Collectors.toMap(TicketCategory::getId, Function.identity())); - } - - for (var categoryWithTickets : sorted) { - var categoryTickets = categoryWithTickets.getValue(); - final int subTotal = categoryTickets.stream().mapToInt(TicketPriceContainer::getSummarySrcPriceCts).sum(); - final int subTotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(categoryTickets); - var firstTicket = categoryTickets.get(0); - final int ticketPriceCts = firstTicket.getSummarySrcPriceCts(); - final int priceBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(firstTicket)); - String categoryName = categoriesById.get(categoryWithTickets.getKey()).getName(); - summary.add(new SummaryRow(categoryName, formatCents(ticketPriceCts, currencyCode), formatCents(priceBeforeVat, currencyCode), categoryTickets.size(), formatCents(subTotal, currencyCode), formatCents(subTotalBeforeVat, currencyCode), subTotal, SummaryType.TICKET, null)); - var ticketVatStatus = firstTicket.getVatStatus(); - if (VatStatus.isVatExempt(ticketVatStatus) && ticketVatStatus != reservationVatStatus) { - summary.add(new SummaryRow(null, - "", - "", - 0, - formatCents(0, currencyCode, true), - formatCents(0, currencyCode, true), - 0, - SummaryType.TAX_DETAIL, - "0")); - } - } - }); - - summary.addAll(additionalServicesToInclude - .map(entry -> { - String language = locale.getLanguage(); - AdditionalServiceText title = additionalServiceTextRepository.findBestMatchByLocaleAndType(entry.getKey().getId(), language, AdditionalServiceText.TextType.TITLE); - if(!title.getLocale().equals(language) || title.getId() == -1) { - log.debug("additional service {}: title not found for locale {}", title.getAdditionalServiceId(), language); - } - List prices = generateASIPriceContainers(purchaseContext, null).apply(entry).collect(toList()); - AdditionalServiceItemPriceContainer first = prices.get(0); - final int subtotal = prices.stream().mapToInt(AdditionalServiceItemPriceContainer::getSrcPriceCts).sum(); - final int subtotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(prices); - return new SummaryRow(title.getValue(), formatCents(first.getSrcPriceCts(), currencyCode), formatCents(SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(first)), currencyCode), prices.size(), formatCents(subtotal, currencyCode), formatCents(subtotalBeforeVat, currencyCode), subtotal, SummaryType.ADDITIONAL_SERVICE, null); - }).collect(toList())); - - Optional.ofNullable(promoCodeDiscount).ifPresent(promo -> { - String formattedSingleAmount = "-" + (DiscountType.isFixedAmount(promo.getDiscountType()) ? formatCents(promo.getDiscountAmount(), currencyCode) : (promo.getDiscountAmount()+"%")); - summary.add(new SummaryRow(formatPromoCode(promo, ticketsToInclude, locale, purchaseContext), - formattedSingleAmount, - formattedSingleAmount, - reservationCost.getDiscountAppliedCount(), - formatCents(reservationCost.getDiscount(), currencyCode), formatCents(reservationCost.getDiscount(), currencyCode), reservationCost.getDiscount(), - promo.isDynamic() ? SummaryType.DYNAMIC_DISCOUNT : SummaryType.PROMOTION_CODE, - null)); - }); - // - if(purchaseContext instanceof SubscriptionDescriptor) { - if(!subscriptionsToInclude.isEmpty()) { - var subscription = subscriptionsToInclude.get(0); - var priceContainer = new SubscriptionPriceContainer(subscription, promoCodeDiscount, (SubscriptionDescriptor) purchaseContext); - var priceBeforeVat = formatUnit(priceContainer.getNetPrice(), currencyCode); - summary.add(new SummaryRow(purchaseContext.getTitle().get(locale.getLanguage()), - formatCents(priceContainer.getSummarySrcPriceCts(), currencyCode), - priceBeforeVat, - subscriptionsToInclude.size(), - formatCents(priceContainer.getSummarySrcPriceCts() * subscriptionsToInclude.size(), currencyCode), - formatUnit(priceContainer.getNetPrice().multiply(new BigDecimal(subscriptionsToInclude.size())), currencyCode), - priceContainer.getSummarySrcPriceCts(), - SummaryType.SUBSCRIPTION, - null - )); - } - } else if(CollectionUtils.isNotEmpty(subscriptionsToInclude)) { - log.trace("subscriptions to include is not empty"); - var subscription = subscriptionsToInclude.get(0); - subscriptionRepository.findOne(subscription.getSubscriptionDescriptorId(), subscription.getOrganizationId()).ifPresent(subscriptionDescriptor -> { - log.trace("found subscriptionDescriptor with ID {}", subscriptionDescriptor.getId()); - // find tickets with subscription applied - var ticketsSubscription = tickets.stream().filter(t -> Objects.equals(subscription.getId(), t.getSubscriptionId())).collect(toList()); - final int ticketPriceCts = ticketsSubscription.stream().mapToInt(TicketPriceContainer::getSummarySrcPriceCts).sum(); - final int priceBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(ticketsSubscription); - summary.add(new SummaryRow(subscriptionDescriptor.getLocalizedTitle(locale), - "-" + formatCents(ticketPriceCts, currencyCode), - "-" + formatCents(priceBeforeVat, currencyCode), - ticketsSubscription.size(), - "-" + formatCents(ticketPriceCts, currencyCode), - "-" + formatCents(priceBeforeVat, currencyCode), - ticketPriceCts, - SummaryType.APPLIED_SUBSCRIPTION, - null - )); - }); - } - - // - return summary; - } - - List extractSummary(String reservationId, VatStatus reservationVatStatus, - PurchaseContext purchaseContext, Locale locale, PromoCodeDiscount promoCodeDiscount, TotalPrice reservationCost) { - List subscriptionsToInclude; - if(purchaseContext.ofType(PurchaseContextType.event)) { - subscriptionsToInclude = subscriptionRepository.findAppliedSubscriptionByReservationId(reservationId) - .map(List::of) - .orElse(List.of()); - } else { - subscriptionsToInclude = subscriptionRepository.findSubscriptionsByReservationId(reservationId); - } - - return extractSummary(reservationVatStatus, - purchaseContext, - locale, - promoCodeDiscount, - reservationCost, - ticketRepository.findTicketsInReservation(reservationId), - streamAdditionalServiceItems(reservationId, purchaseContext), - subscriptionsToInclude); - } - - private Stream>> streamAdditionalServiceItems(String reservationId, PurchaseContext purchaseContext) { - return purchaseContext.event().map(event -> { - return additionalServiceItemRepository.findByReservationUuid(reservationId) - .stream() - .collect(Collectors.groupingBy(AdditionalServiceItem::getAdditionalServiceId)) - .entrySet() - .stream() - .map(entry -> Pair.of(additionalServiceRepository.getById(entry.getKey(), event.getId()), entry.getValue())); - }).orElse(Stream.empty()); - } - private List>> collectAdditionalServiceItems(String reservationId, Event event) { - return streamAdditionalServiceItems(reservationId, event).collect(Collectors.toList()); + return orderSummaryGenerator.orderSummaryForReservation(reservation, context); } String reservationUrl(String reservationId) { @@ -1836,36 +1188,26 @@ public String reservationUrl(String reservationId, PurchaseContext purchaseConte return reservationUrl(ticketReservationRepository.findReservationById(reservationId), purchaseContext); } - public String reservationUrlForExternalClients(String reservationId, PurchaseContext purchaseContext, String userLanguage, boolean userLoggedIn) { + public String reservationUrlForExternalClients(String reservationId, PurchaseContext purchaseContext, String userLanguage, boolean userLoggedIn, String subscriptionId) { var configMap = configurationManager.getFor(EnumSet.of(BASE_URL, OPENID_PUBLIC_ENABLED), purchaseContext.getConfigurationLevel()); var baseUrl = StringUtils.removeEnd(configMap.get(BASE_URL).getRequiredValue(), "/"); if(userLoggedIn && configMap.get(OPENID_PUBLIC_ENABLED).getValueAsBooleanOrDefault()) { return baseUrl + "/openid/authentication?reservation=" + reservationId + "&contextType=" + purchaseContext.getType() + "&id=" + purchaseContext.getPublicIdentifier(); } else { - return reservationUrl(baseUrl, reservationId, purchaseContext, userLanguage); + var cleanSubscriptionId = StringUtils.trimToNull(subscriptionId); + return ReservationUtil.reservationUrl(baseUrl, reservationId, purchaseContext, userLanguage, cleanSubscriptionId != null ? "subscription="+cleanSubscriptionId : null); } } - String reservationUrl(String baseUrl, String reservationId, PurchaseContext purchaseContext, String userLanguage) { - return StringUtils.removeEnd(baseUrl, "/") + "/" + purchaseContext.getType()+ "/" + purchaseContext.getPublicIdentifier() + "/reservation/" + reservationId + "?lang="+userLanguage; - } - String reservationUrl(TicketReservation reservation, PurchaseContext purchaseContext) { - return reservationUrl(configurationManager.baseUrl(purchaseContext), reservation.getId(), purchaseContext, reservation.getUserLanguage()); + return ReservationUtil.reservationUrl(reservation, purchaseContext, configurationManager); } String ticketUrl(Event event, String ticketId) { Ticket ticket = ticketRepository.findByUUID(ticketId); - return configurationManager.baseUrl(event) + "/event/" + event.getShortName() + "/ticket/" + ticketId + "?lang=" + ticket.getUserLanguage(); } - public String ticketUpdateUrl(Event event, String ticketId) { - Ticket ticket = ticketRepository.findByUUID(ticketId); - - return configurationManager.baseUrl(event) + "/event/" + event.getShortName() + "/ticket/" + ticketId + "/update?lang=" + ticket.getUserLanguage(); - } - public String ticketOnlineCheckIn(Event event, String ticketId) { Ticket ticket = ticketRepository.findByUUID(ticketId); @@ -1922,11 +1264,11 @@ private void cancelReservation(TicketReservation reservation, boolean expired, S } - private void creditReservation(TicketReservation reservation, String username) { + private void creditReservation(TicketReservation reservation, String username, boolean sendEmail) { String reservationId = reservation.getId(); Event event = eventRepository.findByReservationId(reservationId); billingDocumentManager.ensureBillingDocumentIsPresent(event, reservation, username, () -> orderSummaryForReservationId(reservation.getId(), event)); - issueCreditNoteForReservation(event, reservation, username, true); + issueCreditNoteForReservation(event, reservation, username, sendEmail); cleanupReferencesToReservation(false, username, reservationId, event); extensionManager.handleReservationsCreditNoteIssuedForEvent(event, Collections.singletonList(reservationId)); } @@ -1982,10 +1324,6 @@ public Optional findFirstInReservation(String reservationId) { return ticketRepository.findFirstTicketInReservation(reservationId); } - public Optional getVAT(PurchaseContext purchaseContext) { - return configurationManager.getFor(VAT_NR, purchaseContext.getConfigurationLevel()).getValue(); - } - public void updateTicketOwner(Ticket ticket, Locale locale, Event event, @@ -2016,7 +1354,7 @@ public void updateTicketOwner(Ticket ticket, boolean sendTicketAllowed = configurationManager.getFor(SEND_TICKETS_AUTOMATICALLY, ConfigurationLevel.event(event)).getValueAsBooleanOrDefault(); if (sendTicketAllowed && (newTicket.getStatus() == TicketStatus.ACQUIRED || newTicket.getStatus() == TicketStatus.TO_BE_PAID) && (!equalsIgnoreCase(newEmail, ticket.getEmail()) || !equalsIgnoreCase(customerName.getFullName(), ticket.getFullName()))) { - sendTicketByEmail(newTicket, userLocale, event, confirmationTextBuilder); + reservationHelper.sendTicketByEmail(newTicket, userLocale, event, confirmationTextBuilder); } boolean admin = isAdmin(userDetails); @@ -2040,12 +1378,14 @@ public void updateTicketOwner(Ticket ticket, } extensionManager.handleTicketAssignment(newTicket, ticketCategoryRepository.getById(ticket.getCategoryId()), updateTicketOwner.getAdditional()); - + if (isTicketBeingReassigned(ticket, updateTicketOwner, event)) { + invalidateAccess(event, ticket); + } Ticket postUpdateTicket = ticketRepository.findByUUID(ticket.getUuid()); Map postUpdateTicketFields = ticketFieldRepository.findAllByTicketId(ticket.getId()).stream().collect(Collectors.toMap(TicketFieldValue::getName, TicketFieldValue::getValue)); - auditUpdateTicket(preUpdateTicket, preUpdateTicketFields, postUpdateTicket, postUpdateTicketFields, event.getId()); + auditingHelper.auditUpdateTicket(preUpdateTicket, preUpdateTicketFields, postUpdateTicket, postUpdateTicketFields, event.getId()); } boolean isTicketBeingReassigned(Ticket original, UpdateTicketOwnerForm updated, Event event) { @@ -2057,50 +1397,12 @@ boolean isTicketBeingReassigned(Ticket original, UpdateTicketOwnerForm updated, && (!equalsIgnoreCase(original.getEmail(), updated.getEmail()) || !equalsIgnoreCase(original.getFullName(), customerName.getFullName())); } - private void auditUpdateMetadata(String reservationId, - int ticketId, - int eventId, - TicketMetadataContainer newMetadata, - TicketMetadataContainer oldMetadata) { - List> changes = ObjectDiffUtil.diff(oldMetadata, newMetadata, TicketMetadataContainer.class).stream() - .map(this::processChange) - .collect(Collectors.toList()); - - auditingRepository.insert(reservationId, null, eventId, Audit.EventType.UPDATE_TICKET_METADATA, new Date(), - TICKET, Integer.toString(ticketId), changes); - } - - private void auditUpdateTicket(Ticket preUpdateTicket, Map preUpdateTicketFields, Ticket postUpdateTicket, Map postUpdateTicketFields, int eventId) { - List diffTicket = ObjectDiffUtil.diff(preUpdateTicket, postUpdateTicket); - List diffTicketFields = ObjectDiffUtil.diff(preUpdateTicketFields, postUpdateTicketFields); - List> changes = Stream.concat(diffTicket.stream(), diffTicketFields.stream()) - .map(this::processChange) - .collect(Collectors.toList()); - - auditingRepository.insert(preUpdateTicket.getTicketsReservationId(), null, eventId, - Audit.EventType.UPDATE_TICKET, new Date(), TICKET, Integer.toString(preUpdateTicket.getId()), changes); - } - - private HashMap processChange(ObjectDiffUtil.Change change) { - var v = new HashMap(); - v.put("propertyName", change.getPropertyName()); - v.put("state", change.getState()); - v.put("oldValue", change.getOldValue()); - v.put("newValue", change.getNewValue()); - return v; - } private boolean isAdmin(Optional userDetails) { return userDetails.flatMap(u -> u.getAuthorities().stream().map(a -> Role.fromRoleName(a.getAuthority())).filter(Role.ADMIN::equals).findFirst()).isPresent(); } - void sendTicketByEmail(Ticket ticket, Locale locale, Event event, PartialTicketTextGenerator confirmationTextBuilder) { - TicketReservation reservation = ticketReservationRepository.findReservationById(ticket.getTicketsReservationId()); - TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(ticket.getCategoryId(), event.getId()); - notificationManager.sendTicketByEmail(ticket, event, locale, confirmationTextBuilder, reservation, ticketCategory, () -> retrieveAttendeeAdditionalInfoForTicket(ticket)); - } - public Optional> fetchComplete(String eventName, String ticketIdentifier) { return ticketRepository.findOptionalByUUID(ticketIdentifier) .flatMap(ticket -> from(eventName, ticket.getTicketsReservationId(), ticketIdentifier) @@ -2130,7 +1432,7 @@ public Optional> fetchCompleteAndAssign }); } - public Optional fetchCompleteAndAssignedForOnlineCheckIn(String eventName, String ticketIdentifier) { + public Optional fetchCompleteAndAssignedForOnlineCheckIn(String eventName, String ticketIdentifier) { return ticketRepository.getFullInfoForOnlineCheckin(eventName, ticketIdentifier); } @@ -2152,11 +1454,11 @@ public void sendReminderForOfflinePayments() { .forEach(p -> { TicketReservation reservation = p.getLeft(); Event event = p.getMiddle(); - Map model = prepareModelForReservationEmail(event, reservation); + Map model = reservationHelper.prepareModelForReservationEmail(event, reservation); Locale locale = p.getRight(); ticketReservationRepository.flagAsOfflinePaymentReminderSent(reservation.getId()); notificationManager.sendSimpleEmail(event, reservation.getId(), reservation.getEmail(), messageSourceManager.getMessageSourceFor(event).getMessage("reservation.reminder.mail.subject", - new Object[]{getShortReservationID(event, reservation)}, locale), () -> templateManager.renderTemplate(event, TemplateResource.REMINDER_EMAIL, model, locale)); + new Object[]{configurationManager.getShortReservationID(event, reservation)}, locale), () -> templateManager.renderTemplate(event, TemplateResource.REMINDER_EMAIL, model, locale)); }); } @@ -2203,14 +1505,14 @@ private void sendOptionalDataReminder(Pair> eventAndTickets) Event event = eventAndTickets.getLeft(); var messageSource = messageSourceManager.getMessageSourceFor(event); int daysBeforeStart = configurationManager.getFor(ASSIGNMENT_REMINDER_START, ConfigurationLevel.event(event)).getValueAsIntOrDefault(10); - List tickets = eventAndTickets.getRight().stream().filter(t -> !ticketFieldRepository.hasOptionalData(t.getId())).collect(toList()); + List tickets = eventAndTickets.getRight().stream().filter(t -> !ticketFieldRepository.hasOptionalData(t.getId())).toList(); Set notYetNotifiedReservations = tickets.stream().map(Ticket::getTicketsReservationId).distinct().filter(rid -> findByIdForNotification(rid, clockProvider.withZone(event.getZoneId()), daysBeforeStart).isPresent()).collect(toSet()); tickets.stream() .filter(t -> notYetNotifiedReservations.contains(t.getTicketsReservationId())) .forEach(t -> { int result = ticketRepository.flagTicketAsReminderSent(t.getId()); Validate.isTrue(result == 1); - Map model = TemplateResource.prepareModelForReminderTicketAdditionalInfo(organizationRepository.getById(event.getOrganizationId()), event, t, ticketUpdateUrl(event, t.getUuid())); + Map model = TemplateResource.prepareModelForReminderTicketAdditionalInfo(organizationRepository.getById(event.getOrganizationId()), event, t, ReservationUtil.ticketUpdateUrl(event, t, configurationManager)); Locale locale = Optional.ofNullable(t.getUserLanguage()).map(LocaleUtil::forLanguageTag).orElseGet(() -> findReservationLanguage(t.getTicketsReservationId())); notificationManager.sendSimpleEmail(event, t.getTicketsReservationId(), t.getEmail(), messageSource.getMessage("reminder.ticket-additional-info.subject", new Object[]{event.getDisplayName()}, locale), () -> templateManager.renderTemplate(event, TemplateResource.REMINDER_TICKET_ADDITIONAL_INFO, model, locale)); @@ -2240,7 +1542,7 @@ private void sendAssignmentReminder(Pair> p) { .filter(Optional::isPresent) .map(Optional::get) .forEach(reservation -> { - Map model = prepareModelForReservationEmail(event, reservation); + Map model = reservationHelper.prepareModelForReservationEmail(event, reservation); ticketReservationRepository.updateLatestReminderTimestamp(reservation.getId(), ZonedDateTime.now(clockProvider.withZone(eventZoneId))); Locale locale = findReservationLanguage(reservation.getId()); notificationManager.sendSimpleEmail(event, reservation.getId(), reservation.getEmail(), messageSource.getMessage("reminder.ticket-not-assigned.subject", @@ -2266,9 +1568,6 @@ public String getShortReservationID(Configurable event, String reservationId) { return configurationManager.getShortReservationID(event, findById(reservationId).orElseThrow()); } - public String getShortReservationID(Configurable event, TicketReservation reservation) { - return configurationManager.getShortReservationID(event, reservation); - } public int countAvailableTickets(EventAndOrganizationId event, TicketCategory category) { if(category.isBounded()) { @@ -2291,6 +1590,7 @@ public void releaseTicket(Event event, TicketReservation ticketReservation, fina throw new IllegalStateException("Cannot release reserved tickets"); } // + invalidateAccess(event, ticket); String reservationId = ticketReservation.getId(); //#365 - reset UUID when releasing a ticket @@ -2327,6 +1627,10 @@ public void releaseTicket(Event event, TicketReservation ticketReservation, fina extensionManager.handleTicketCancelledForEvent(event, Collections.singletonList(ticket.getUuid())); } + private void invalidateAccess(Event event, Ticket ticket) { + applicationEventPublisher.publishEvent(new InvalidateAccess(ticket, ticketRepository.getTicketMetadata(ticket.getId()), event)); + } + int getReservationTimeout(Configurable configurable) { return configurationManager.getFor(RESERVATION_TIMEOUT, configurable.getConfigurationLevel()).getValueAsIntOrDefault(25); } @@ -2336,9 +1640,9 @@ public void validateAndConfirmOfflinePayment(String reservationId, Event event, Optional optionalOrderSummary = optionally(() -> orderSummaryForReservationId(reservation.getId(), event)); Validate.isTrue(optionalOrderSummary.isPresent(), "Reservation not found"); OrderSummary orderSummary = optionalOrderSummary.orElseThrow(); - var currencyCode = orderSummary.getOriginalTotalPrice().getCurrencyCode(); - Validate.isTrue(MonetaryUtil.centsToUnit(orderSummary.getOriginalTotalPrice().getPriceWithVAT(), currencyCode).compareTo(paidAmount) == 0, "paid price differs from due price"); - confirmOfflinePayment(event, reservation.getId(), username); + var currencyCode = orderSummary.getOriginalTotalPrice().currencyCode(); + Validate.isTrue(MonetaryUtil.centsToUnit(orderSummary.getOriginalTotalPrice().priceWithVAT(), currencyCode).compareTo(paidAmount) == 0, "paid price differs from due price"); + confirmOfflinePayment(event, reservation.getId(), null, username); } public List getPendingPayments(String eventName) { @@ -2356,7 +1660,7 @@ public List> findAllInvoices(int eventI Map documentsByReservationId = documents.stream().collect(toMap(BillingDocument::getReservationId, Function.identity())); return ticketReservationRepository.findByIds(documentsByReservationId.keySet()).stream() .map(r -> Pair.of(r, documentsByReservationId.get(r.getId()))) - .collect(toList()); + .toList(); } public Stream>> streamAllDocumentsFor(int eventId) { @@ -2368,8 +1672,8 @@ public Stream>> str .map(entry -> Pair.of(reservations.get(entry.getKey()), entry.getValue())); } - public Integer countInvoices(int eventId) { - return ticketReservationRepository.countInvoices(eventId); + public Integer countBillingDocuments(int eventId) { + return billingDocumentRepository.countAllForEvent(eventId); } @@ -2381,7 +1685,7 @@ public int revertTicketsToFreeIfAccessRestricted(int eventId) { List restrictedCategories = ticketCategoryRepository.findAllTicketCategories(eventId).stream() .filter(TicketCategory::isAccessRestricted) .map(TicketCategory::getId) - .collect(toList()); + .toList(); if(!restrictedCategories.isEmpty()) { int count = ticketRepository.revertToFreeForRestrictedCategories(eventId, restrictedCategories); if(count > 0) { @@ -2462,6 +1766,10 @@ public void setReservationOwner(String reservationId, ); } + public void setReservationMetadata(String reservationId, ReservationMetadata metadata) { + Validate.isTrue(ticketReservationRepository.setMetadata(reservationId, metadata) == 1, "Error while updating metadata"); + } + static String buildCompleteBillingAddress(CustomerName customerName, String billingAddressCompany, String billingAddressLine1, @@ -2496,10 +1804,6 @@ public void updateReservationInvoicingAdditionalInformation(String reservationId ticketReservationRepository.updateInvoicingAdditionalInformation(reservationId, json.asJsonString(ticketReservationInvoicingAdditionalInfo)); } - private static Locale getReservationLocale(TicketReservation reservation) { - return StringUtils.isEmpty(reservation.getUserLanguage()) ? Locale.ENGLISH : LocaleUtil.forLanguageTag(reservation.getUserLanguage()); - } - public PaymentWebhookResult processTransactionWebhook(String body, String signature, PaymentProxy paymentProxy, Map additionalInfo) { return processTransactionWebhook(body, signature, paymentProxy, additionalInfo, new PaymentContext()); } @@ -2570,36 +1874,31 @@ private PaymentWebhookResult handlePaymentWebhookResult(PurchaseContext purchase String operationType, boolean moveToWatingExternalConfirmationAllowed) { - switch(paymentWebhookResult.getType()) { - case NOT_RELEVANT: { - log.trace("Discarding event {} for reservation {}", operationType, reservation.getId()); - break; - } - case TRANSACTION_INITIATED: { - if(reservation.getStatus() == EXTERNAL_PROCESSING_PAYMENT && moveToWatingExternalConfirmationAllowed) { + switch (paymentWebhookResult.getType()) { + case NOT_RELEVANT -> log.trace("Discarding event {} for reservation {}", operationType, reservation.getId()); + case TRANSACTION_INITIATED -> { + if (reservation.getStatus() == EXTERNAL_PROCESSING_PAYMENT && moveToWatingExternalConfirmationAllowed) { String status = WAITING_EXTERNAL_CONFIRMATION.name(); log.trace("Event {} received. Setting status {} for reservation {}", operationType, status, reservation.getId()); ticketReservationRepository.updateReservationStatus(reservation.getId(), status); } else { log.trace("Ignoring Event {}, as it cannot be applied for reservation {} ({})", operationType, reservation.getId(), reservation.getStatus()); } - break; } - case SUCCESSFUL: { + case SUCCESSFUL -> { log.trace("Event {} for reservation {} has been successfully processed.", operationType, reservation.getId()); var totalPrice = totalReservationCostWithVAT(reservation).getLeft(); var paymentToken = paymentWebhookResult.getPaymentToken(); var paymentSpecification = new PaymentSpecification(reservation, totalPrice, purchaseContext, paymentToken, - orderSummaryForReservation(reservation, purchaseContext), true, eventHasPrivacyPolicy(purchaseContext)); - transitionToComplete(paymentSpecification, totalPrice, paymentToken.getPaymentProvider(), null); - break; + orderSummaryForReservation(reservation, purchaseContext), true, hasPrivacyPolicy(purchaseContext)); + transitionToComplete(paymentSpecification, paymentToken.getPaymentProvider(), null); } - case FAILED: { + case FAILED -> { // depending on when we actually receive the event, we could have two possibilities: // // 1) the user is still waiting on the payment page. In this case, there's no harm in reverting the reservation status to PENDING - // 2) the user has given up and we're officially in background mode. + // 2) the user has given up, and we're officially in background mode. // // either way, we have to notify the user about the charge failure. Then: // @@ -2612,25 +1911,23 @@ private PaymentWebhookResult handlePaymentWebhookResult(PurchaseContext purchase Date now = new Date(); int slackTime = configurationManager.getFor(RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT, paymentContext.getConfigurationLevel()).getValueAsIntOrDefault(10); PaymentMethod paymentMethodForTransaction = paymentProvider.getPaymentMethodForTransaction(transaction); - if(expiration.before(now)) { + if (expiration.before(now)) { sendTransactionFailedEmail(purchaseContext, reservation, paymentMethodForTransaction, paymentWebhookResult, true); cancelReservation(reservation, false, null); break; - } else if(DateUtils.addMinutes(expiration, -slackTime).before(now)) { + } else if (DateUtils.addMinutes(expiration, -slackTime).before(now)) { ticketReservationRepository.updateValidity(reservation.getId(), DateUtils.addMinutes(now, slackTime)); } reTransitionToPending(reservation.getId(), false); purchaseContext.event().ifPresent(event -> sendTransactionFailedEmail(event, reservation, paymentMethodForTransaction, paymentWebhookResult, false)); - break; } - case CANCELLED: { + case CANCELLED -> { reTransitionToPending(reservation.getId(), false); log.debug("Event {} for reservation {} has been cancelled", operationType, reservation.getId()); - break; } - default: + default -> { // do nothing for ERROR/REJECTED - break; + } } return paymentWebhookResult; } @@ -2647,21 +1944,16 @@ public Optional forceTransactionCheck(PurchaseContext purchaseCon var paymentWebhookResult = providerAndWebhookResult.getRight(); handlePaymentWebhookResult(purchaseContext, providerAndWebhookResult.getLeft(), paymentWebhookResult, reservation, transaction, paymentContext, "force-check", true); - switch(paymentWebhookResult.getType()) { - case FAILED: - case REJECTED: - case CANCELLED: - return PaymentResult.failed(paymentWebhookResult.getReason()); - case NOT_RELEVANT: - case ERROR: + return switch (paymentWebhookResult.getType()) { + case FAILED, REJECTED, CANCELLED -> PaymentResult.failed(paymentWebhookResult.getReason()); + case NOT_RELEVANT, ERROR -> // to be on the safe side, we ignore errors when trying to reload the payment // because they could be caused by network/availability problems - return PaymentResult.pending(transaction.getPaymentId()); - case TRANSACTION_INITIATED: - return StringUtils.isNotEmpty(paymentWebhookResult.getRedirectUrl()) ? PaymentResult.redirect(paymentWebhookResult.getRedirectUrl()) : PaymentResult.pending(transaction.getPaymentId()); - default: - return PaymentResult.successful(paymentWebhookResult.getPaymentToken().getToken()); - } + PaymentResult.pending(transaction.getPaymentId()); + case TRANSACTION_INITIATED -> + StringUtils.isNotEmpty(paymentWebhookResult.getRedirectUrl()) ? PaymentResult.redirect(paymentWebhookResult.getRedirectUrl()) : PaymentResult.pending(transaction.getPaymentId()); + default -> PaymentResult.successful(paymentWebhookResult.getPaymentToken().getToken()); + }; }); } @@ -2683,7 +1975,7 @@ private boolean reservationStatusNotCompatible(TicketReservation reservation) { } private void sendTransactionFailedEmail(PurchaseContext purchaseContext, TicketReservation reservation, PaymentMethod paymentMethod, PaymentWebhookResult paymentWebhookResult, boolean cancelReservation) { - var shortReservationID = getShortReservationID(purchaseContext, reservation); + var shortReservationID = configurationManager.getShortReservationID(purchaseContext, reservation); var messageSource = messageSourceManager.getMessageSourceFor(purchaseContext); Map model = Map.of( ORGANIZATION, organizationRepository.getById(purchaseContext.getOrganizationId()), @@ -2691,7 +1983,7 @@ private void sendTransactionFailedEmail(PurchaseContext purchaseContext, TicketR "reservation", reservation, RESERVATION_ID, shortReservationID, "eventName", purchaseContext.getDisplayName(), - "provider", requireNonNullElse(paymentMethod.name(), ""), + "provider", requireNonNullElse(paymentMethod, PaymentMethod.NONE).name(), "reason", paymentWebhookResult.getReason(), "reservationUrl", reservationUrl(reservation, purchaseContext)); @@ -2759,9 +2051,17 @@ public Optional createSubscriptionReservation(SubscriptionDescriptor sub Locale locale, BindingResult bindingResult, Principal principal) { + return createSubscriptionReservation(subscriptionDescriptor, locale, bindingResult, principal, SubscriptionMetadata.empty()); + } + + public Optional createSubscriptionReservation(SubscriptionDescriptor subscriptionDescriptor, + Locale locale, + BindingResult bindingResult, + Principal principal, + SubscriptionMetadata metadata) { Date expiration = DateUtils.addMinutes(new Date(), getReservationTimeout(subscriptionDescriptor)); try { - return Optional.of(createSubscriptionReservation(subscriptionDescriptor, expiration, locale, retrievePublicUserId(principal))); + return Optional.of(createSubscriptionReservation(subscriptionDescriptor, expiration, locale, retrievePublicUserId(principal), metadata)); } catch (CannotProceedWithPayment cannotProceedWithPayment) { bindingResult.reject("error.STEP_1_PAYMENT_METHODS_ERROR"); log.error("missing payment methods", cannotProceedWithPayment); @@ -2790,13 +2090,13 @@ public Optional createTicketReservation(Event event, false, principal); return Optional.of(reservationId); - } catch (TicketReservationManager.NotEnoughTicketsException nete) { + } catch (NotEnoughTicketsException nete) { bindingResult.reject(ErrorsCode.STEP_1_NOT_ENOUGH_TICKETS); - } catch (TicketReservationManager.MissingSpecialPriceTokenException missing) { + } catch (MissingSpecialPriceTokenException missing) { bindingResult.reject(ErrorsCode.STEP_1_ACCESS_RESTRICTED); - } catch (TicketReservationManager.InvalidSpecialPriceTokenException invalid) { + } catch (InvalidSpecialPriceTokenException invalid) { bindingResult.reject(ErrorsCode.STEP_1_CODE_NOT_FOUND); - } catch (TicketReservationManager.TooManyTicketsForDiscountCodeException tooMany) { + } catch (TooManyTicketsForDiscountCodeException tooMany) { bindingResult.reject(ErrorsCode.STEP_2_DISCOUNT_CODE_USAGE_EXCEEDED); } catch (CannotProceedWithPayment cannotProceedWithPayment) { bindingResult.reject(ErrorsCode.STEP_1_CATEGORIES_NOT_COMPATIBLE); @@ -2812,7 +2112,7 @@ boolean canProceedWithPayment(PurchaseContext purchaseContext, TotalPrice totalP var categoriesInReservation = ticketRepository.getCategoriesIdToPayInReservation(reservationId); var blacklistedPaymentMethods = configurationManager.getBlacklistedMethodsForReservation(purchaseContext, categoriesInReservation); var transactionRequest = new TransactionRequest(totalPrice, ticketReservationRepository.getBillingDetailsForReservation(reservationId)); - var availableMethods = paymentManager.getPaymentMethods(purchaseContext, transactionRequest).stream().filter(pm -> pm.getStatus() == PaymentMethodStatus.ACTIVE && pm.getPaymentMethod() != PaymentMethod.NONE).collect(toList()); + var availableMethods = paymentManager.getPaymentMethods(purchaseContext, transactionRequest).stream().filter(pm -> pm.getStatus() == PaymentMethodStatus.ACTIVE && pm.getPaymentMethod() != PaymentMethod.NONE).toList(); if(availableMethods.isEmpty() || availableMethods.stream().allMatch(pm -> blacklistedPaymentMethods.contains(pm.getPaymentMethod()))) { log.error("Cannot proceed with reservation. No payment methods available {} or all blacklisted {}", availableMethods, blacklistedPaymentMethods); return false; @@ -2844,8 +2144,7 @@ public void flagAsValidated(String reservationId, PurchaseContext purchaseContex private void checkOfflinePaymentsForEvent(Event event) { log.trace("check offline payments for event {}", event.getShortName()); var paymentContext = new PaymentContext(event); - var providers = paymentManager.streamActiveProvidersByProxyAndCapabilities(PaymentProxy.OFFLINE, paymentContext, List.of(OfflineProcessor.class)) - .collect(toList()); + var providers = paymentManager.streamActiveProvidersByProxyAndCapabilities(PaymentProxy.OFFLINE, paymentContext, List.of(OfflineProcessor.class)).toList(); if(providers.isEmpty()) { log.trace("No active offline provider has been found. Exiting..."); return; @@ -2919,12 +2218,12 @@ private void processResults(Event event, Map tr.getTicketReservation().getId()).collect(toList())); + pendingReview.addAll(byStatus.getOrDefault(Transaction.Status.OFFLINE_PENDING_REVIEW, List.of()).stream().map(tr -> tr.getTicketReservation().getId()).toList()); } private boolean automaticConfirmOfflinePayment(Event event, String reservationId) { try { - confirmOfflinePayment(event, reservationId, null); + confirmOfflinePayment(event, reservationId, null, null); return true; } catch(Exception ex) { log.warn("Unable to confirm reservation "+reservationId, ex); @@ -3057,15 +2356,15 @@ boolean applySubscriptionCode(int eventId, var purchaseContext = purchaseContextManager.findByReservationId(reservation.getId()).orElseThrow(); ticketReservationRepository.updateBillingData(reservation.getVatStatus(), calculateSrcPrice(purchaseContext.getVatStatus(), totalPrice), - totalPrice.getPriceWithVAT(), - totalPrice.getVAT(), - Math.abs(totalPrice.getDiscount()), + totalPrice.priceWithVAT(), + totalPrice.VAT(), + Math.abs(totalPrice.discount()), purchaseContext.getCurrency(), reservation.getVatNr(), reservation.getVatCountryCode(), reservation.isInvoiceRequested(), reservation.getId()); - log.trace("subscription applied. totalPrice is {}", totalPrice.getPriceWithVAT()); + log.trace("subscription applied. totalPrice is {}", totalPrice.priceWithVAT()); return true; } @@ -3116,9 +2415,7 @@ public Optional findSubscriptionDetails(TicketRese } public Map> retrieveAttendeeAdditionalInfoForTicket(Ticket ticket) { - return ticketFieldRepository.findNameAndValue(ticket.getId()) - .stream() - .collect(groupingBy(FieldNameAndValue::getName, mapping(FieldNameAndValue::getValue, toList()))); + return reservationHelper.retrieveAttendeeAdditionalInfoForTicket(ticket); } private Integer retrievePublicUserId(Principal principal) { diff --git a/src/main/java/alfio/manager/UploadedResourceManager.java b/src/main/java/alfio/manager/UploadedResourceManager.java index c31b936979..22a9e593e8 100644 --- a/src/main/java/alfio/manager/UploadedResourceManager.java +++ b/src/main/java/alfio/manager/UploadedResourceManager.java @@ -19,8 +19,9 @@ import alfio.model.UploadedResource; import alfio.model.modification.UploadBase64FileModification; import alfio.repository.UploadedResourceRepository; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -38,9 +39,10 @@ @Component @Transactional -@Log4j2 public class UploadedResourceManager { + private static final Logger log = LoggerFactory.getLogger(UploadedResourceManager.class); + public static final String ATTR_IMG_WIDTH = "width"; public static final String ATTR_IMG_HEIGHT = "height"; @@ -93,7 +95,7 @@ public Optional saveResource(UploadBase64FileModification file) { uploadedResourceRepository.delete(file.getName()); } - return Optional.ofNullable(uploadedResourceRepository.upload(null, null, file, getAttributes(file))); + return Optional.of(uploadedResourceRepository.upload(null, null, file, getAttributes(file))); } public Optional saveResource(int organizationId, UploadBase64FileModification file) { @@ -101,7 +103,7 @@ public Optional saveResource(int organizationId, UploadBase64FileModifi uploadedResourceRepository.delete(organizationId, file.getName()); } - return Optional.ofNullable(uploadedResourceRepository.upload(organizationId, null, file, getAttributes(file))); + return Optional.of(uploadedResourceRepository.upload(organizationId, null, file, getAttributes(file))); } public Optional saveResource(int organizationId, int eventId, UploadBase64FileModification file) { diff --git a/src/main/java/alfio/manager/WaitingQueueManager.java b/src/main/java/alfio/manager/WaitingQueueManager.java index 5d58752e29..94cfe807bf 100644 --- a/src/main/java/alfio/manager/WaitingQueueManager.java +++ b/src/main/java/alfio/manager/WaitingQueueManager.java @@ -30,11 +30,11 @@ import alfio.repository.user.OrganizationRepository; import alfio.util.*; import ch.digitalfondue.npjt.AffectedRowCountAndKey; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Component; @@ -48,10 +48,10 @@ import static alfio.util.EventUtil.determineAvailableSeats; @Component -@Log4j2 -@AllArgsConstructor public class WaitingQueueManager { + private static final Logger log = LoggerFactory.getLogger(WaitingQueueManager.class); + private final WaitingQueueRepository waitingQueueRepository; private final TicketRepository ticketRepository; private final TicketCategoryRepository ticketCategoryRepository; @@ -65,6 +65,32 @@ public class WaitingQueueManager { private final ExtensionManager extensionManager; private final ClockProvider clockProvider; + public WaitingQueueManager(WaitingQueueRepository waitingQueueRepository, + TicketRepository ticketRepository, + TicketCategoryRepository ticketCategoryRepository, + ConfigurationManager configurationManager, + EventStatisticsManager eventStatisticsManager, + NotificationManager notificationManager, + TemplateManager templateManager, + MessageSourceManager messageSourceManager, + OrganizationRepository organizationRepository, + EventRepository eventRepository, + ExtensionManager extensionManager, + ClockProvider clockProvider) { + this.waitingQueueRepository = waitingQueueRepository; + this.ticketRepository = ticketRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.configurationManager = configurationManager; + this.eventStatisticsManager = eventStatisticsManager; + this.notificationManager = notificationManager; + this.templateManager = templateManager; + this.messageSourceManager = messageSourceManager; + this.organizationRepository = organizationRepository; + this.eventRepository = eventRepository; + this.extensionManager = extensionManager; + this.clockProvider = clockProvider; + } + public boolean subscribe(Event event, CustomerName customerName, String email, Integer selectedCategoryId, Locale userLanguage) { try { if(configurationManager.getFor(STOP_WAITING_QUEUE_SUBSCRIPTIONS, ConfigurationLevel.event(event)).getValueAsBooleanOrDefault()) { diff --git a/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java b/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java index d37e23ac0c..1bf07cc9c6 100644 --- a/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java +++ b/src/main/java/alfio/manager/WaitingQueueSubscriptionProcessor.java @@ -29,9 +29,9 @@ import alfio.util.ClockProvider; import alfio.util.TemplateManager; import alfio.util.TemplateResource; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; @@ -51,10 +51,10 @@ @Component @Transactional -@RequiredArgsConstructor -@Log4j2 public class WaitingQueueSubscriptionProcessor { + private static final Logger log = LoggerFactory.getLogger(WaitingQueueSubscriptionProcessor.class); + private final EventManager eventManager; private final TicketReservationManager ticketReservationManager; private final ConfigurationManager configurationManager; @@ -67,6 +67,30 @@ public class WaitingQueueSubscriptionProcessor { private final PlatformTransactionManager transactionManager; private final ClockProvider clockProvider; + public WaitingQueueSubscriptionProcessor(EventManager eventManager, + TicketReservationManager ticketReservationManager, + ConfigurationManager configurationManager, + WaitingQueueManager waitingQueueManager, + NotificationManager notificationManager, + WaitingQueueRepository waitingQueueRepository, + MessageSourceManager messageSourceManager, + TemplateManager templateManager, + TicketRepository ticketRepository, + PlatformTransactionManager transactionManager, + ClockProvider clockProvider) { + this.eventManager = eventManager; + this.ticketReservationManager = ticketReservationManager; + this.configurationManager = configurationManager; + this.waitingQueueManager = waitingQueueManager; + this.notificationManager = notificationManager; + this.waitingQueueRepository = waitingQueueRepository; + this.messageSourceManager = messageSourceManager; + this.templateManager = templateManager; + this.ticketRepository = ticketRepository; + this.transactionManager = transactionManager; + this.clockProvider = clockProvider; + } + public void handleWaitingTickets() { Map> activeEvents = eventManager.getActiveEvents().stream() .collect(Collectors.partitioningBy(this::isWaitingListFormEnabled)); diff --git a/src/main/java/alfio/manager/i18n/MessageSourceManager.java b/src/main/java/alfio/manager/i18n/MessageSourceManager.java index 549dc5d4a5..b661972bd2 100644 --- a/src/main/java/alfio/manager/i18n/MessageSourceManager.java +++ b/src/main/java/alfio/manager/i18n/MessageSourceManager.java @@ -16,12 +16,10 @@ */ package alfio.manager.i18n; -import alfio.model.Event; import alfio.model.PurchaseContext; import alfio.repository.system.ConfigurationRepository; import alfio.util.CustomResourceBundleMessageSource; import alfio.util.LocaleUtil; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; import org.springframework.context.MessageSource; import org.springframework.context.support.AbstractMessageSource; @@ -32,12 +30,21 @@ import java.util.Map; import java.util.Set; import java.util.function.Function; +import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; -@Log4j2 public class MessageSourceManager { + /** + * No-op filter used to load all keys in the resource bundle, to be used with the new Admin frontend + */ + public static final Predicate ADMIN_FRONTEND = key -> true; + /** + * Filters out all the "admin" keys which would not make sense to load on the public frontend + */ + public static final Predicate PUBLIC_FRONTEND = key -> !key.startsWith("admin."); + private static final Pattern ARGUMENT_FINDER = Pattern.compile("\\{+(\\d+)}+"); private final CustomResourceBundleMessageSource messageSource; private final ConfigurationRepository configurationRepository; @@ -100,12 +107,16 @@ private static Map convertPlaceholders(Map bundl return res; } - public Map getBundleAsMap(String baseName, boolean withSystemOverride, String lang) { + public Map getBundleAsMap(String baseName, + boolean withSystemOverride, + String lang, + Predicate keysFilter) { var locale = LocaleUtil.forLanguageTag(lang); - var messageSource = getRootMessageSource(withSystemOverride); + var rootMessageSource = getRootMessageSource(withSystemOverride); return getKeys(baseName, locale) .stream() - .collect(Collectors.toMap(Function.identity(), k -> convertPlaceholder(messageSource.getMessage(k, EMPTY_ARRAY, locale)))); + .filter(keysFilter) + .collect(Collectors.toMap(Function.identity(), k -> convertPlaceholder(rootMessageSource.getMessage(k, EMPTY_ARRAY, locale)))); } private static class MessageSourceWithOverride extends AbstractMessageSource { diff --git a/src/main/java/alfio/manager/openid/AdminOpenIdAuthenticationManager.java b/src/main/java/alfio/manager/openid/AdminOpenIdAuthenticationManager.java index bdfb7784ff..d6eadfce8e 100644 --- a/src/main/java/alfio/manager/openid/AdminOpenIdAuthenticationManager.java +++ b/src/main/java/alfio/manager/openid/AdminOpenIdAuthenticationManager.java @@ -27,8 +27,7 @@ import alfio.repository.user.join.UserOrganizationRepository; import alfio.util.Json; import com.auth0.jwt.interfaces.Claim; -import lombok.SneakyThrows; -import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.concurrent.ConcurrentException; import org.apache.commons.lang3.concurrent.LazyInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,12 +38,11 @@ import java.net.http.HttpClient; import java.util.*; import java.util.regex.Pattern; -import java.util.stream.Collectors; -@Log4j2 public class AdminOpenIdAuthenticationManager extends BaseOpenIdAuthenticationManager { - private final Logger logger = LoggerFactory.getLogger(AdminOpenIdAuthenticationManager.class); + private static final Logger log = LoggerFactory.getLogger(AdminOpenIdAuthenticationManager.class); + private static final String ALFIO_ADMIN = "ALFIO_ADMIN"; private final LazyConfigurationContainer configurationContainer; @@ -74,9 +72,9 @@ public AdminOpenIdAuthenticationManager(Environment environment, @Override protected OpenIdAlfioUser fromToken(String idToken, String subject, String email, Map idTokenClaims) { - List groupsList = idTokenClaims.get(openIdConfiguration().getRolesParameter()).asList(String.class); + List groupsList = idTokenClaims.get(openIdConfiguration().rolesParameter()).asList(String.class); log.trace("IdToken contains the following groups: {}", groupsList); - List groups = groupsList.stream().filter(group -> group.startsWith("ALFIO_")).collect(Collectors.toList()); + List groups = groupsList.stream().filter(group -> group.startsWith("ALFIO_")).toList(); boolean isAdmin = groups.contains(ALFIO_ADMIN); if (isAdmin) { @@ -88,21 +86,25 @@ protected OpenIdAlfioUser fromToken(String idToken, String subject, String email if(groups.isEmpty()){ String message = "Users must have at least a group called ALFIO_ADMIN or ALFIO_BACKOFFICE"; - logger.error(message); + log.error(message); throw new RuntimeException(message); } - List alfioOrganizationAuthorizationsRaw = idTokenClaims.get(openIdConfiguration().getAlfioGroupsParameter()).asList(String.class); + List alfioOrganizationAuthorizationsRaw = idTokenClaims.get(openIdConfiguration().alfioGroupsParameter()).asList(String.class); log.trace("IdToken contains the following alfioGroups: {}", alfioOrganizationAuthorizationsRaw); Map> alfioOrganizationAuthorizations = extractOrganizationRoles(alfioOrganizationAuthorizationsRaw); Set alfioRoles = extractAlfioRoles(alfioOrganizationAuthorizations); return new OpenIdAlfioUser(idToken, subject, email, getUserType(), alfioRoles, alfioOrganizationAuthorizations); } - @SneakyThrows + @Override protected OpenIdConfiguration openIdConfiguration() { - return configurationContainer.get(); + try { + return configurationContainer.get(); + } catch (ConcurrentException e) { + throw new IllegalStateException(e); + } } private Set extractAlfioRoles(Map> alfioOrganizationAuthorizations) { @@ -122,10 +124,10 @@ public List getScopes() { "openid", "email", "profile", - openIdConfiguration.getRolesParameter(), - openIdConfiguration.getAlfioGroupsParameter(), - openIdConfiguration.getGivenNameClaim(), - openIdConfiguration.getFamilyNameClaim() + openIdConfiguration.rolesParameter(), + openIdConfiguration.alfioGroupsParameter(), + openIdConfiguration.givenNameClaim(), + openIdConfiguration.familyNameClaim() ); } @@ -178,6 +180,5 @@ protected OpenIdConfiguration initialize() { return OpenIdConfiguration.from(environment, configurationManager); } } - } diff --git a/src/main/java/alfio/manager/openid/BaseOpenIdAuthenticationManager.java b/src/main/java/alfio/manager/openid/BaseOpenIdAuthenticationManager.java index 51c402827f..7f2a92876f 100644 --- a/src/main/java/alfio/manager/openid/BaseOpenIdAuthenticationManager.java +++ b/src/main/java/alfio/manager/openid/BaseOpenIdAuthenticationManager.java @@ -32,8 +32,9 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.interfaces.Claim; import com.fasterxml.jackson.core.type.TypeReference; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.core.GrantedAuthority; @@ -53,8 +54,10 @@ import static alfio.util.HttpUtils.APPLICATION_FORM_URLENCODED; import static alfio.util.HttpUtils.APPLICATION_JSON; -@Log4j2 abstract class BaseOpenIdAuthenticationManager implements OpenIdAuthenticationManager { + + private static final Logger log = LoggerFactory.getLogger(OpenIdAuthenticationManager.class); + protected static final String CODE = "code"; protected static final String ID_TOKEN = "id_token"; protected static final String SUBJECT = "sub"; @@ -126,8 +129,8 @@ private OpenIdAlfioAuthentication createOrRetrieveUser(OpenIdAlfioUser user, var configuration = openIdConfiguration(); var result = userRepository.create(user.getEmail(), passwordEncoder.encode(PasswordGenerator.generateRandomPassword()), - retrieveClaimOrBlank(idTokenClaims, configuration.getGivenNameClaim()), - retrieveClaimOrBlank(idTokenClaims, configuration.getFamilyNameClaim()), + retrieveClaimOrBlank(idTokenClaims, configuration.givenNameClaim()), + retrieveClaimOrBlank(idTokenClaims, configuration.familyNameClaim()), user.getEmail(), true, getUserType(), @@ -217,15 +220,15 @@ private void updateRoles(Set roles, String username) { @Override public String buildAuthorizeUrl(String state) { - log.trace("buildAuthorizeUrl, configuration: {}", this::openIdConfiguration); + log.trace("buildAuthorizeUrl, configuration: {}", openIdConfiguration()); String scopeParameter = String.join("+", getScopes()); UriComponents uri = UriComponentsBuilder.newInstance() .scheme(HTTPS) - .host(openIdConfiguration().getDomain()) - .path(openIdConfiguration().getAuthenticationUrl()) - .queryParam(REDIRECT_URI, openIdConfiguration().getCallbackURI()) - .queryParam("client_id", openIdConfiguration().getClientId()) + .host(openIdConfiguration().domain()) + .path(openIdConfiguration().authenticationUrl()) + .queryParam(REDIRECT_URI, openIdConfiguration().callbackURI()) + .queryParam("client_id", openIdConfiguration().clientId()) .queryParam("state", state) .queryParam("scope", scopeParameter) .queryParam("response_type", "code") @@ -237,8 +240,8 @@ public String buildAuthorizeUrl(String state) { public String buildClaimsRetrieverUrl() { UriComponents uri = UriComponentsBuilder.newInstance() .scheme(HTTPS) - .host(openIdConfiguration().getDomain()) - .path(openIdConfiguration().getTokenEndpoint()) + .host(openIdConfiguration().domain()) + .path(openIdConfiguration().tokenEndpoint()) .build(); return uri.toUriString(); } @@ -247,16 +250,16 @@ public String buildClaimsRetrieverUrl() { public String buildLogoutUrl() { UriComponents uri = UriComponentsBuilder.newInstance() .scheme(HTTPS) - .host(openIdConfiguration().getDomain()) - .path(openIdConfiguration().getLogoutUrl()) - .queryParam(REDIRECT_URI, openIdConfiguration().getLogoutRedirectUrl()) + .host(openIdConfiguration().domain()) + .path(openIdConfiguration().logoutUrl()) + .queryParam(REDIRECT_URI, openIdConfiguration().logoutRedirectUrl()) .build(); return uri.toString(); } @Override public String buildRetrieveClaimsUrlBody(String code) { - var contentType = openIdConfiguration().getContentType(); + var contentType = openIdConfiguration().contentType(); if (contentType.equals(APPLICATION_JSON)) { return buildAccessTokenUrlJson(code); } @@ -270,9 +273,9 @@ private String buildAccessTokenUrlJson(String code) { Map body = Map.of( "grant_type", "authorization_code", "code", code, - "client_id", openIdConfiguration().getClientId(), - "client_secret", openIdConfiguration().getClientSecret(), - REDIRECT_URI, openIdConfiguration().getCallbackURI() + "client_id", openIdConfiguration().clientId(), + "client_secret", openIdConfiguration().clientSecret(), + REDIRECT_URI, openIdConfiguration().callbackURI() ); return json.asJsonString(body); } @@ -280,16 +283,16 @@ REDIRECT_URI, openIdConfiguration().getCallbackURI() private String buildAccessTokenUrlForm(String code) { return "grant_type=authorization_code" + "&code=" + code + - "&client_id=" + openIdConfiguration().getClientId() + - "&client_secret=" + openIdConfiguration().getClientSecret() + - "&redirect_uri=" + openIdConfiguration().getCallbackURI(); + "&client_id=" + openIdConfiguration().clientId() + + "&client_secret=" + openIdConfiguration().clientSecret() + + "&redirect_uri=" + openIdConfiguration().callbackURI(); } private Map retrieveAccessToken(String code){ try { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(buildClaimsRetrieverUrl())) - .header("Content-Type", openIdConfiguration().getContentType()) + .header("Content-Type", openIdConfiguration().contentType()) .POST(HttpRequest.BodyPublishers.ofString(buildRetrieveClaimsUrlBody(code))) .build(); diff --git a/src/main/java/alfio/manager/openid/OpenIdConfiguration.java b/src/main/java/alfio/manager/openid/OpenIdConfiguration.java index 33c1a3658f..6c3b17e166 100644 --- a/src/main/java/alfio/manager/openid/OpenIdConfiguration.java +++ b/src/main/java/alfio/manager/openid/OpenIdConfiguration.java @@ -21,31 +21,26 @@ import alfio.model.system.ConfigurationKeys; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; + import org.springframework.core.env.Environment; import static java.util.Objects.requireNonNullElse; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.removeEnd; -@Getter -@Setter -public class OpenIdConfiguration { - private final String domain; - private final String clientId; - private final String clientSecret; - private final String callbackURI; - private final String authenticationUrl; - private final String tokenEndpoint; - private final String givenNameClaim; - private final String familyNameClaim; - private final String contentType; - private final String rolesParameter; - private final String alfioGroupsParameter; - private final String logoutUrl; - private final String logoutRedirectUrl; - +public record OpenIdConfiguration(String domain, + String clientId, + String clientSecret, + String callbackURI, + String authenticationUrl, + String tokenEndpoint, + String givenNameClaim, + String familyNameClaim, + String contentType, + String rolesParameter, + String alfioGroupsParameter, + String logoutUrl, + String logoutRedirectUrl) { @JsonCreator public OpenIdConfiguration(@JsonProperty("domain") String domain, @JsonProperty("clientId") String clientId, @@ -81,7 +76,7 @@ public static OpenIdConfiguration from(Environment environment, ConfigurationMan environment.getProperty("openid.domain"), environment.getProperty("openid.clientId"), environment.getProperty("openid.clientSecret"), - environment.getProperty("openid.callbackURI",baseUrl + "/callback"), + environment.getProperty("openid.callbackURI", baseUrl + "/callback"), environment.getProperty("openid.authenticationUrl"), environment.getProperty("openid.tokenEndpoint", "/authorize"), environment.getProperty("openid.givenNameClaim"), @@ -95,16 +90,16 @@ public static OpenIdConfiguration from(Environment environment, ConfigurationMan } public String toString() { - return "OpenIdConfiguration(domain=" + this.getDomain() - + ", clientId=" + (isNotBlank(this.getClientId()) ? "" : "missing") - + ", clientSecret=" + (isNotBlank(this.getClientSecret()) ? "" : "missing") - + ", callbackURI=" + this.getCallbackURI() - + ", authenticationUrl=" + this.getAuthenticationUrl() - + ", tokenEndpoint=" + this.getTokenEndpoint() - + ", contentType=" + this.getContentType() - + ", rolesParameter=" + this.getRolesParameter() - + ", alfioGroupsParameter=" + this.getAlfioGroupsParameter() - + ", logoutUrl=" + this.getLogoutUrl() - + ", logoutRedirectUrl=" + this.getLogoutRedirectUrl() + ")"; + return "OpenIdConfiguration(domain=" + this.domain() + + ", clientId=" + (isNotBlank(this.clientId()) ? "" : "missing") + + ", clientSecret=" + (isNotBlank(this.clientSecret()) ? "" : "missing") + + ", callbackURI=" + this.callbackURI() + + ", authenticationUrl=" + this.authenticationUrl() + + ", tokenEndpoint=" + this.tokenEndpoint() + + ", contentType=" + this.contentType() + + ", rolesParameter=" + this.rolesParameter() + + ", alfioGroupsParameter=" + this.alfioGroupsParameter() + + ", logoutUrl=" + this.logoutUrl() + + ", logoutRedirectUrl=" + this.logoutRedirectUrl() + ")"; } } diff --git a/src/main/java/alfio/manager/payment/BankTransferManager.java b/src/main/java/alfio/manager/payment/BankTransferManager.java index 549a5e4a3d..02d942fdf8 100644 --- a/src/main/java/alfio/manager/payment/BankTransferManager.java +++ b/src/main/java/alfio/manager/payment/BankTransferManager.java @@ -18,6 +18,7 @@ import alfio.manager.support.PaymentResult; import alfio.manager.system.ConfigurationManager; +import alfio.model.Event; import alfio.model.PurchaseContext; import alfio.model.TicketReservation; import alfio.model.system.ConfigurationKeys; @@ -26,9 +27,9 @@ import alfio.repository.TransactionRepository; import alfio.util.ClockProvider; import alfio.util.WorkingDaysAdjusters; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.time.ZonedDateTime; @@ -40,18 +41,29 @@ import static alfio.model.system.ConfigurationKeys.*; @Component -@Log4j2 -@AllArgsConstructor public class BankTransferManager implements PaymentProvider { + private static final Logger log = LoggerFactory.getLogger(BankTransferManager.class); + private static final EnumSet OPTIONS_TO_LOAD = EnumSet.of(BANK_TRANSFER_ENABLED, DEFERRED_BANK_TRANSFER_ENABLED, OFFLINE_PAYMENT_DAYS, REVOLUT_ENABLED, REVOLUT_API_KEY, REVOLUT_LIVE_MODE, REVOLUT_MANUAL_REVIEW); + private final ConfigurationManager configurationManager; private final TicketReservationRepository ticketReservationRepository; private final TransactionRepository transactionRepository; private final ClockProvider clockProvider; + public BankTransferManager(ConfigurationManager configurationManager, + TicketReservationRepository ticketReservationRepository, + TransactionRepository transactionRepository, + ClockProvider clockProvider) { + this.configurationManager = configurationManager; + this.ticketReservationRepository = ticketReservationRepository; + this.transactionRepository = transactionRepository; + this.clockProvider = clockProvider; + } + @Override public Set getSupportedPaymentMethods(PaymentContext paymentContext, TransactionRequest transactionRequest) { return EnumSet.of(PaymentMethod.BANK_TRANSFER); @@ -151,14 +163,24 @@ public static OptionalInt getOfflinePaymentWaitingPeriod(PaymentContext paymentC private static OptionalInt getOfflinePaymentWaitingPeriod(PurchaseContext purchaseContext, int configuredValue) { ZonedDateTime now = purchaseContext.now(ClockProvider.clock()); - ZonedDateTime eventBegin = purchaseContext.getBegin(); - int daysToBegin = (int) ChronoUnit.DAYS.between(now.toLocalDate(), eventBegin.toLocalDate()); + ZonedDateTime maxDate = purchaseContext.event() + .map(BankTransferManager::getMaxPaymentDate) + .orElse(purchaseContext.getBegin()); + int daysToBegin = (int) ChronoUnit.DAYS.between(now.toLocalDate(), maxDate.toLocalDate()); if (daysToBegin < 0) { return OptionalInt.empty(); } return OptionalInt.of( Math.min(daysToBegin, configuredValue) ); } + private static ZonedDateTime getMaxPaymentDate(Event event) { + if (event.getSameDay()) { + return event.getBegin(); + } else { + return event.getEnd(); + } + } + @Override public boolean accept(Transaction transaction) { return PaymentProxy.OFFLINE == transaction.getPaymentProxy(); diff --git a/src/main/java/alfio/manager/payment/BaseStripeManager.java b/src/main/java/alfio/manager/payment/BaseStripeManager.java index 004bc7a2ff..e3e37088e8 100644 --- a/src/main/java/alfio/manager/payment/BaseStripeManager.java +++ b/src/main/java/alfio/manager/payment/BaseStripeManager.java @@ -41,8 +41,8 @@ import com.stripe.model.Refund; import com.stripe.net.RequestOptions; import com.stripe.net.Webhook; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; @@ -52,10 +52,10 @@ import static alfio.model.system.ConfigurationKeys.*; -@Log4j2 -@AllArgsConstructor class BaseStripeManager { + private static final Logger log = LoggerFactory.getLogger(BaseStripeManager.class); + static final String STRIPE_MANAGER_TYPE_KEY = "stripeManagerType"; static final String SUCCEEDED = "succeeded"; static final String PENDING = "pending"; @@ -76,6 +76,16 @@ class BaseStripeManager { Stripe.setAppInfo("Alf.io", "2.x", "https://alf.io"); } + BaseStripeManager(ConfigurationManager configurationManager, + ConfigurationRepository configurationRepository, + TicketRepository ticketRepository, + Environment environment) { + this.configurationManager = configurationManager; + this.configurationRepository = configurationRepository; + this.ticketRepository = ticketRepository; + this.environment = environment; + } + String getSecretKey(Configurable configurable) { return configurationManager.getFor(STRIPE_SECRET_KEY, configurable.getConfigurationLevel()).getRequiredValue(); } @@ -110,8 +120,7 @@ Optional processWebhookEvent(String body, String signature) { try { com.stripe.model.Event event = Webhook.constructEvent(body, signature, getWebhookSignatureKey()); if("account.application.deauthorized".equals(event.getType()) - && event.getLivemode() != null - && event.getLivemode() == environment.acceptsProfiles(Profiles.of("dev", "test", "demo"))) { + && Boolean.TRUE.equals(event.getLivemode()) == environment.acceptsProfiles(Profiles.of("dev", "test", "demo"))) { return Optional.of(revokeToken(event.getAccount())); } return Optional.of(true); @@ -194,10 +203,14 @@ PaymentResult getToken(PaymentSpecification spec) { return PaymentResult.failed(ErrorsCode.STEP_2_MISSING_STRIPE_TOKEN); } - private BalanceTransaction retrieveBalanceTransaction(String balanceTransaction, RequestOptions options) throws StripeException { + BalanceTransaction retrieveBalanceTransaction(String balanceTransaction, RequestOptions options) throws StripeException { return BalanceTransaction.retrieve(balanceTransaction, options); } + Charge retrieveCharge(String chargeId, RequestOptions requestOptions) throws StripeException { + return Charge.retrieve(chargeId, requestOptions); + } + Optional options(PurchaseContext purchaseContext) { return options(purchaseContext, UnaryOperator.identity()); } @@ -227,10 +240,10 @@ Optional getInfo(Transaction transaction, PurchaseContext pu Optional requestOptionsOptional = options(purchaseContext); if(requestOptionsOptional.isPresent()) { RequestOptions options = requestOptionsOptional.get(); - Charge charge = Charge.retrieve(transaction.getTransactionId(), options); + Charge charge = retrieveCharge(transaction.getTransactionId(), options); String paidAmount = MonetaryUtil.formatCents(charge.getAmount(), charge.getCurrency()); String refundedAmount = MonetaryUtil.formatCents(charge.getAmountRefunded(), charge.getCurrency()); - List fees = retrieveBalanceTransaction(charge.getBalanceTransaction(), options).getFeeDetails(); + List fees = retrieveBalanceTransaction(charge.getBalanceTransaction(), options).getFeeDetails(); return Optional.of(new PaymentInformation(paidAmount, refundedAmount, getFeeAmount(fees, "stripe_fee"), getFeeAmount(fees, "application_fee"))); } return Optional.empty(); @@ -239,11 +252,11 @@ Optional getInfo(Transaction transaction, PurchaseContext pu } } - static String getFeeAmount(List fees, String feeType) { + static String getFeeAmount(List fees, String feeType) { return fees.stream() .filter(f -> f.getType().equals(feeType)) .findFirst() - .map(BalanceTransaction.Fee::getAmount) + .map(BalanceTransaction.FeeDetail::getAmount) .map(String::valueOf) .orElse(null); } diff --git a/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java b/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java index 9d6fdcd80c..f111aab129 100644 --- a/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java +++ b/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java @@ -19,7 +19,6 @@ import alfio.manager.support.PaymentResult; import alfio.model.transaction.*; import alfio.repository.TicketReservationRepository; -import lombok.extern.log4j.Log4j2; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -30,7 +29,6 @@ @Component @Order(0) -@Log4j2 public class DeferredBankTransferManager implements PaymentProvider { private final TicketReservationRepository ticketReservationRepository; diff --git a/src/main/java/alfio/manager/payment/MetadataBuilder.java b/src/main/java/alfio/manager/payment/MetadataBuilder.java index 22ba7e5a49..d72dd5555d 100644 --- a/src/main/java/alfio/manager/payment/MetadataBuilder.java +++ b/src/main/java/alfio/manager/payment/MetadataBuilder.java @@ -16,19 +16,19 @@ */ package alfio.manager.payment; -import lombok.experimental.UtilityClass; import org.apache.commons.lang3.StringUtils; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -@UtilityClass -class MetadataBuilder { - +final class MetadataBuilder { static final String RESERVATION_ID = "reservationId"; + private MetadataBuilder() { + } + static Map buildMetadata(PaymentSpecification spec, Map base) { Map initialMetadata = new HashMap<>(base); initialMetadata.put(RESERVATION_ID, spec.getReservationId()); diff --git a/src/main/java/alfio/manager/payment/MollieConnectManager.java b/src/main/java/alfio/manager/payment/MollieConnectManager.java index 9c4f314203..47e3a6f79f 100644 --- a/src/main/java/alfio/manager/payment/MollieConnectManager.java +++ b/src/main/java/alfio/manager/payment/MollieConnectManager.java @@ -27,10 +27,9 @@ import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.builder.api.DefaultApi20; import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.model.OAuthConfig; import com.github.scribejava.core.oauth.OAuth20Service; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.net.http.HttpClient; @@ -41,23 +40,32 @@ import static alfio.model.system.ConfigurationKeys.*; -@AllArgsConstructor -@Log4j2 @Component public class MollieConnectManager implements OAuthPaymentProviderConnector { + + private static final Logger log = LoggerFactory.getLogger(MollieConnectManager.class); + public static final String MOLLIE_CONNECT_REDIRECT_PATH = "/admin/configuration/payment/mollie/authorize"; private static final String SCOPES = "payments.read payments.write refunds.read refunds.write"; private final ExtensionManager extensionManager; private final ConfigurationManager configurationManager; private final HttpClient httpClient; + public MollieConnectManager(ExtensionManager extensionManager, + ConfigurationManager configurationManager, + HttpClient httpClient) { + this.extensionManager = extensionManager; + this.configurationManager = configurationManager; + this.httpClient = httpClient; + } + @Override public AuthorizationRequestDetails getConnectURL(int organizationId) { var options = configurationManager.getFor(Set.of(MOLLIE_API_KEY, MOLLIE_CONNECT_CLIENT_ID, MOLLIE_CONNECT_CALLBACK, BASE_URL), ConfigurationLevel.organization(organizationId)); String callbackURL = options.get(MOLLIE_CONNECT_CALLBACK).getValueOrDefault(options.get(BASE_URL).getRequiredValue() + MOLLIE_CONNECT_REDIRECT_PATH); String state = extensionManager.generateOAuth2StateParam(organizationId).orElse(UUID.randomUUID().toString()); - OAuthConfig config = new OAuthConfig(options.get(MOLLIE_CONNECT_CLIENT_ID).getRequiredValue(), options.get(MOLLIE_API_KEY).getRequiredValue(), callbackURL, SCOPES, null, state, "code", null, null, null); - return new AuthorizationRequestDetails(new MollieConnectApi().getAuthorizationUrl(config, Collections.emptyMap()), state); + return new AuthorizationRequestDetails(new MollieConnectApi() + .getAuthorizationUrl("code", options.get(MOLLIE_CONNECT_CLIENT_ID).getRequiredValue(), callbackURL, SCOPES, state, Collections.emptyMap()), state); } @Override diff --git a/src/main/java/alfio/manager/payment/MollieWebhookPaymentManager.java b/src/main/java/alfio/manager/payment/MollieWebhookPaymentManager.java index 0de1a58e37..a8448f613e 100644 --- a/src/main/java/alfio/manager/payment/MollieWebhookPaymentManager.java +++ b/src/main/java/alfio/manager/payment/MollieWebhookPaymentManager.java @@ -37,16 +37,16 @@ import alfio.repository.TicketReservationRepository; import alfio.repository.TransactionRepository; import alfio.util.*; -import alfio.util.oauth2.AccessTokenResponseDetails; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import lombok.AllArgsConstructor; import lombok.Data; -import lombok.extern.log4j.Log4j2; +import lombok.Getter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.util.UriComponentsBuilder; @@ -70,10 +70,10 @@ import static java.nio.charset.StandardCharsets.UTF_8; @Component -@Log4j2 -@AllArgsConstructor public class MollieWebhookPaymentManager implements PaymentProvider, WebhookHandler, RefundRequest, PaymentInfo { + private static final Logger log = LoggerFactory.getLogger(MollieWebhookPaymentManager.class); + public static final String WEBHOOK_URL_TEMPLATE = "/api/payment/webhook/mollie/reservation/{reservationId}"; private static final Set EMPTY_METHODS = Collections.unmodifiableSet(EnumSet.noneOf(PaymentMethod.class)); static final Map SUPPORTED_METHODS = Map.of( @@ -123,6 +123,24 @@ public class MollieWebhookPaymentManager implements PaymentProvider, WebhookHand private final ClockProvider clockProvider; private final PurchaseContextManager purchaseContextManager; + public MollieWebhookPaymentManager(HttpClient client, + ConfigurationManager configurationManager, + TicketReservationRepository ticketReservationRepository, + TicketRepository ticketRepository, + TransactionRepository transactionRepository, + MollieConnectManager mollieConnectManager, + ClockProvider clockProvider, + PurchaseContextManager purchaseContextManager) { + this.client = client; + this.configurationManager = configurationManager; + this.ticketReservationRepository = ticketReservationRepository; + this.ticketRepository = ticketRepository; + this.transactionRepository = transactionRepository; + this.mollieConnectManager = mollieConnectManager; + this.clockProvider = clockProvider; + this.purchaseContextManager = purchaseContextManager; + } + private HttpRequest.Builder requestFor(String url, Map configuration, ConfigurationLevel configurationLevel) { // check if platform mode is active boolean platformMode = configurationLevel.getOrganizationId().isPresent() && configuration.get(PLATFORM_MODE_ENABLED).getValueAsBooleanOrDefault(); @@ -130,8 +148,8 @@ private HttpRequest.Builder requestFor(String url, Map { var accessTokenResponseDetails = mollieConnectManager.refreshAccessToken(configuration); - if(accessTokenResponseDetails.isSuccess()) { - return accessTokenResponseDetails.getAccessToken(); + if(accessTokenResponseDetails.success()) { + return accessTokenResponseDetails.accessToken(); } throw new IllegalStateException("cannot refresh access token"); })); @@ -274,7 +292,7 @@ private PaymentResult getPaymentResult(PaymentSpecification spec) { log.warn("Request interrupted while trying to init payment", e); return PaymentResult.failed(ErrorsCode.STEP_2_PAYMENT_REQUEST_CREATION); } catch (Exception e) { - log.warn(e); + log.warn("Error while getting the payment result", e); return PaymentResult.failed(ErrorsCode.STEP_2_PAYMENT_REQUEST_CREATION); } } @@ -547,12 +565,12 @@ public boolean refund(Transaction transaction, PurchaseContext purchaseContext, try { var response = client.send(request, HttpResponse.BodyHandlers.ofString()); if(HttpUtils.callSuccessful(response)) { - log.trace("Received a successful response from Mollie. Body is {}", response::body); + log.trace("Received a successful response from Mollie. Body is {}", response.body()); // we ignore the answer, for now return true; } else { log.warn("got {} response while calling refund API for payment ID {}", response.statusCode(), paymentId); - log.trace("detailed reply from mollie: {}", response::body); + log.trace("detailed reply from mollie: {}", response.body()); return false; } } catch (InterruptedException e) { @@ -598,29 +616,37 @@ private static MethodCacheKey from(TransactionRequest transactionRequest, Map configuration) { String billingCountry = null; - if(transactionRequest.getBillingDetails() != null) { - billingCountry = StringUtils.trimToNull(transactionRequest.getBillingDetails().getCountry()); + if(transactionRequest.billingDetails() != null) { + billingCountry = StringUtils.trimToNull(transactionRequest.billingDetails().getCountry()); } PaymentAmount amount = null; - if(transactionRequest.getPrice() != null) { - String currencyCode = transactionRequest.getPrice().getCurrencyCode(); - amount = new PaymentAmount(formatCents(transactionRequest.getPrice().getPriceWithVAT(), currencyCode), currencyCode); + if(transactionRequest.price() != null) { + String currencyCode = transactionRequest.price().currencyCode(); + amount = new PaymentAmount(formatCents(transactionRequest.price().priceWithVAT(), currencyCode), currencyCode); } boolean testMode = !configuration.get(MOLLIE_CONNECT_LIVE_MODE).getValueAsBooleanOrDefault(); return new MethodCacheKey(amount, billingCountry, testMode); } } - @Data + @Getter public static class PaymentAmount { private final String value; private final String currency; + + public PaymentAmount(String value, String currency) { + this.value = value; + this.currency = currency; + } } - @AllArgsConstructor private static class MolliePaymentDetails { private final JsonObject body; + private MolliePaymentDetails(JsonObject body) { + this.body = body; + } + String getReservationId() { return Objects.requireNonNull(body.getAsJsonObject("metadata").get(MetadataBuilder.RESERVATION_ID), "reservation id") .getAsString(); diff --git a/src/main/java/alfio/manager/payment/OnSiteManager.java b/src/main/java/alfio/manager/payment/OnSiteManager.java index 88307bfcc9..2e25a416c7 100644 --- a/src/main/java/alfio/manager/payment/OnSiteManager.java +++ b/src/main/java/alfio/manager/payment/OnSiteManager.java @@ -21,8 +21,6 @@ import alfio.model.system.ConfigurationPathLevel; import alfio.model.transaction.*; import alfio.repository.TransactionRepository; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -36,14 +34,17 @@ import static alfio.model.system.ConfigurationKeys.RECAPTCHA_API_KEY; @Component -@Log4j2 -@AllArgsConstructor @Transactional public class OnSiteManager implements PaymentProvider { private final ConfigurationManager configurationManager; private final TransactionRepository transactionRepository; + public OnSiteManager(ConfigurationManager configurationManager, TransactionRepository transactionRepository) { + this.configurationManager = configurationManager; + this.transactionRepository = transactionRepository; + } + @Override public Set getSupportedPaymentMethods(PaymentContext paymentContext, TransactionRequest transactionRequest) { return EnumSet.of(PaymentMethod.ON_SITE); diff --git a/src/main/java/alfio/manager/payment/PayPalManager.java b/src/main/java/alfio/manager/payment/PayPalManager.java index d34eeaa580..b0f013e820 100644 --- a/src/main/java/alfio/manager/payment/PayPalManager.java +++ b/src/main/java/alfio/manager/payment/PayPalManager.java @@ -40,13 +40,13 @@ import com.paypal.http.exceptions.HttpException; import com.paypal.orders.*; import com.paypal.payments.CapturesRefundRequest; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.HmacAlgorithms; import org.apache.commons.codec.digest.HmacUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.util.UriComponentsBuilder; @@ -58,17 +58,16 @@ import java.time.ZonedDateTime; import java.util.*; import java.util.function.Supplier; -import java.util.stream.Collectors; import static alfio.model.system.ConfigurationKeys.PAYPAL_ENABLED; import static alfio.util.MonetaryUtil.*; import static org.apache.commons.collections4.CollectionUtils.emptyIfNull; @Component -@Log4j2 -@AllArgsConstructor public class PayPalManager implements PaymentProvider, RefundRequest, PaymentInfo, ExtractPaymentTokenFromTransaction { + private static final Logger log = LoggerFactory.getLogger(PayPalManager.class); + private final Cache cachedClients = Caffeine.newBuilder() .expireAfterAccess(Duration.ofHours(1L)) .build(); @@ -79,6 +78,20 @@ public class PayPalManager implements PaymentProvider, RefundRequest, PaymentInf private final Json json; private final ClockProvider clockProvider; + public PayPalManager(ConfigurationManager configurationManager, + TicketReservationRepository ticketReservationRepository, + TicketRepository ticketRepository, + TransactionRepository transactionRepository, + Json json, + ClockProvider clockProvider) { + this.configurationManager = configurationManager; + this.ticketReservationRepository = ticketReservationRepository; + this.ticketRepository = ticketRepository; + this.transactionRepository = transactionRepository; + this.json = json; + this.clockProvider = clockProvider; + } + private PayPalHttpClient getClient(Configurable configurable) { PayPalEnvironment apiContext = getApiContext(configurable); return cachedClients.get(generateKey(apiContext), key -> new PayPalHttpClient(apiContext)); @@ -232,8 +245,7 @@ private Optional getInfo(Transaction transaction, PurchaseCo if(HttpUtils.statusCodeIsSuccessful(orderResponse.statusCode()) && orderResponse.result() != null) { var order = orderResponse.result(); var payments = order.purchaseUnits().stream() - .map(PurchaseUnit::payments) - .collect(Collectors.toList()); + .map(PurchaseUnit::payments).toList(); var refund = payments.stream().flatMap(p -> emptyIfNull(p.refunds()).stream()) .map(r -> new BigDecimal(r.amount().value())) @@ -349,7 +361,7 @@ public PaymentResult getToken(PaymentSpecification spec) { } return PaymentResult.redirect(createCheckoutRequest(spec)); } catch (Exception e) { - log.error(e); + log.error("error while getting the token", e); return PaymentResult.failed( ErrorsCode.STEP_2_PAYMENT_REQUEST_CREATION ); } } @@ -413,11 +425,8 @@ public void removeToken(TicketReservation reservation, String paymentId) { } } - @AllArgsConstructor - private static class PayPalChargeDetails { - private final String captureId; - private final String orderId; - private final long payPalFee; + + private record PayPalChargeDetails(String captureId, String orderId, long payPalFee) { } } diff --git a/src/main/java/alfio/manager/payment/PaymentManagerUtils.java b/src/main/java/alfio/manager/payment/PaymentManagerUtils.java index 36a1dea128..ec1560b5c5 100644 --- a/src/main/java/alfio/manager/payment/PaymentManagerUtils.java +++ b/src/main/java/alfio/manager/payment/PaymentManagerUtils.java @@ -18,13 +18,16 @@ import alfio.model.transaction.PaymentProxy; import alfio.repository.TransactionRepository; -import lombok.experimental.UtilityClass; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -@UtilityClass -@Log4j2 -class PaymentManagerUtils { +final class PaymentManagerUtils { + + private static final Logger log = LoggerFactory.getLogger(PaymentManagerUtils.class); + + private PaymentManagerUtils() { + } static void invalidateExistingTransactions(String reservationId, TransactionRepository transactionRepository) { invalidateExistingTransactions(reservationId, transactionRepository, null); diff --git a/src/main/java/alfio/manager/payment/PaymentSpecification.java b/src/main/java/alfio/manager/payment/PaymentSpecification.java index cec14d826f..c6187ca8d7 100644 --- a/src/main/java/alfio/manager/payment/PaymentSpecification.java +++ b/src/main/java/alfio/manager/payment/PaymentSpecification.java @@ -87,7 +87,7 @@ public PaymentSpecification(TicketReservation reservation, OrderSummary orderSummary, boolean tcAccepted, boolean privacyAccepted) { - this(reservation.getId(), gatewayToken, totalPrice.getPriceWithVAT(), + this(reservation.getId(), gatewayToken, totalPrice.priceWithVAT(), purchaseContext, reservation.getEmail(), new CustomerName(reservation.getFullName(), reservation.getFirstName(), reservation.getLastName(), true), reservation.getBillingAddress(), reservation.getCustomerReference(), LocaleUtil.forLanguageTag(reservation.getUserLanguage()), reservation.isInvoiceRequested(), !reservation.isDirectAssignmentRequested(), orderSummary, reservation.getVatCountryCode(), diff --git a/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java b/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java index c8b37ee1fc..e84a1bd6c2 100644 --- a/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java +++ b/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java @@ -31,13 +31,12 @@ import alfio.util.ClockProvider; import alfio.util.Json; import alfio.util.MonetaryUtil; -import alfio.util.oauth2.AccessTokenResponseDetails; import com.fasterxml.jackson.core.type.TypeReference; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; @@ -52,7 +51,6 @@ import java.time.ZonedDateTime; import java.util.*; import java.util.function.Predicate; -import java.util.stream.Collectors; import static alfio.model.system.ConfigurationKeys.*; import static alfio.util.EventUtil.JSON_DATETIME_FORMATTER; @@ -60,10 +58,10 @@ @Component @Order(1) @Transactional -@Log4j2 -@AllArgsConstructor public class RevolutBankTransferManager implements PaymentProvider, OfflineProcessor, PaymentInfo { + private static final Logger log = LoggerFactory.getLogger(RevolutBankTransferManager.class); + private static final String GENERIC_ERROR = "error"; private final BankTransferManager bankTransferManager; private final ConfigurationManager configurationManager; @@ -74,6 +72,18 @@ public class RevolutBankTransferManager implements PaymentProvider, OfflineProce .expireAfterWrite(Duration.ofHours(1)) .build(); + public RevolutBankTransferManager(BankTransferManager bankTransferManager, + ConfigurationManager configurationManager, + TransactionRepository transactionRepository, + HttpClient client, + ClockProvider clockProvider) { + this.bankTransferManager = bankTransferManager; + this.configurationManager = configurationManager; + this.transactionRepository = transactionRepository; + this.client = client; + this.clockProvider = clockProvider; + } + @Override public Set getSupportedPaymentMethods(PaymentContext paymentContext, TransactionRequest transactionRequest) { return bankTransferManager.getSupportedPaymentMethods(paymentContext, transactionRequest); @@ -134,8 +144,7 @@ Result> matchTransactions(Collection> matched = pendingReservations.stream() .map(reservation -> Pair.of(reservation, transactions.stream().filter(transactionMatches(reservation, context)).findFirst())) .filter(pair -> pair.getRight().isPresent()) - .map(pair -> Pair.of(pair.getLeft(), pair.getRight().orElseThrow())) - .collect(Collectors.toList()); + .map(pair -> Pair.of(pair.getLeft(), pair.getRight().orElseThrow())).toList(); return Result.success(matched.stream().map(pair -> { var reservationId = pair.getLeft().getTicketReservation().getId(); @@ -158,7 +167,7 @@ Result> matchTransactions(Collection transactionMatches(TicketReservationWithTransaction reservationWithTransaction, PaymentContext context) { @@ -195,7 +204,7 @@ private Result> loadTransactions(ZonedDateTim return Result.success( result.stream() .filter(t -> "completed".equals(t.getState()) && t.getLegs().size() == 1 && accounts.contains(t.getLegs().get(0).getAccountId())) - .collect(Collectors.toList())); + .toList()); } return Result.error(ErrorCode.custom("no data received", "No data received from Revolut. Status code is "+response.statusCode())); } catch (InterruptedException e) { @@ -227,7 +236,7 @@ private List loadAccountsFromAPI(String revolutKey, String baseUrl) { if (response.statusCode() == HttpStatus.OK.value()) { List> result = Json.fromJson(response.body(), new TypeReference<>() { }); - return result.stream().filter(m -> "active".equals(m.get("state"))).map(m -> (String) m.get("id")).collect(Collectors.toList()); + return result.stream().filter(m -> "active".equals(m.get("state"))).map(m -> (String) m.get("id")).toList(); } throw new IllegalStateException("cannot retrieve accounts"); } catch (IllegalStateException ex) { diff --git a/src/main/java/alfio/manager/payment/SaferpayManager.java b/src/main/java/alfio/manager/payment/SaferpayManager.java index 2a608b7b77..46115fe100 100644 --- a/src/main/java/alfio/manager/payment/SaferpayManager.java +++ b/src/main/java/alfio/manager/payment/SaferpayManager.java @@ -35,9 +35,7 @@ import alfio.util.ClockProvider; import alfio.util.HttpUtils; import alfio.util.MonetaryUtil; -import alfio.util.oauth2.AccessTokenResponseDetails; import com.google.gson.JsonParser; -import lombok.AllArgsConstructor; import lombok.experimental.Delegate; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.time.DateUtils; @@ -61,7 +59,6 @@ @Component @Transactional -@AllArgsConstructor public class SaferpayManager implements PaymentProvider, /*RefundRequest,*/ PaymentInfo, WebhookHandler { private static final String LIVE_ENDPOINT = "https://www.saferpay.com/api"; @@ -78,6 +75,20 @@ public class SaferpayManager implements PaymentProvider, /*RefundRequest,*/ Paym private final TicketRepository ticketRepository; private final ClockProvider clockProvider; + public SaferpayManager(ConfigurationManager configurationManager, + HttpClient httpClient, + TicketReservationRepository ticketReservationRepository, + TransactionRepository transactionRepository, + TicketRepository ticketRepository, + ClockProvider clockProvider) { + this.configurationManager = configurationManager; + this.httpClient = httpClient; + this.ticketReservationRepository = ticketReservationRepository; + this.transactionRepository = transactionRepository; + this.ticketRepository = ticketRepository; + this.clockProvider = clockProvider; + } + @Override public Set getSupportedPaymentMethods(PaymentContext paymentContext, TransactionRequest transactionRequest) { return EnumSet.of(PaymentMethod.CREDIT_CARD); @@ -139,13 +150,14 @@ public PaymentResult doPayment(PaymentSpecification spec) { var description = purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) ? "ticket(s) for event" : "x subscription"; var paymentDescription = String.format("%s - %d %s %s", configurationManager.getShortReservationID(purchaseContext, reservation), items, description, purchaseContext.getDisplayName()); - var requestBody = new PaymentPageInitializeRequestBuilder(configuration.get(BASE_URL).getRequiredValue(), spec) - .addAuthentication(configuration.get(SAFERPAY_CUSTOMER_ID).getRequiredValue(), reservationId, configuration.get(SAFERPAY_TERMINAL_ID).getRequiredValue()) - .addOrderInformation(reservationId, Integer.toString(spec.getPriceWithVAT()), spec.getCurrencyCode(), paymentDescription, retryCount) - .build(); - var request = buildRequest(configuration, "/Payment/v1/PaymentPage/Initialize", requestBody); + try { + var requestBody = new PaymentPageInitializeRequestBuilder(configuration.get(BASE_URL).getRequiredValue(), spec) + .addAuthentication(configuration.get(SAFERPAY_CUSTOMER_ID).getRequiredValue(), reservationId, configuration.get(SAFERPAY_TERMINAL_ID).getRequiredValue()) + .addOrderInformation(reservationId, Integer.toString(spec.getPriceWithVAT()), spec.getCurrencyCode(), paymentDescription, retryCount) + .build(); + var request = buildRequest(configuration, "/Payment/v1/PaymentPage/Initialize", requestBody); var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); if(!HttpUtils.callSuccessful(response)) { LOGGER.warn("Create session failed with status {}, body {}", response.statusCode(), response.body()); @@ -217,12 +229,11 @@ public boolean requiresSignedBody() { @Override public Optional getInfo(Transaction transaction, PurchaseContext purchaseContext) { var configuration = loadConfiguration(purchaseContext); - var requestBody = new TransactionInquireRequestBuilder(transaction.getTransactionId(), 0) - .addAuthentication(configuration.get(SAFERPAY_CUSTOMER_ID).getRequiredValue(), transaction.getReservationId()) - .build(); - var request = buildRequest(configuration, "/Payment/v1/Transaction/Inquire", requestBody); - try { + var requestBody = new TransactionInquireRequestBuilder(transaction.getTransactionId(), 0) + .addAuthentication(configuration.get(SAFERPAY_CUSTOMER_ID).getRequiredValue(), transaction.getReservationId()) + .build(); + var request = buildRequest(configuration, "/Payment/v1/Transaction/Inquire", requestBody); var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); if(!HttpUtils.callSuccessful(response)) { LOGGER.warn("Cannot retrieve transaction info. Status {}, body {}", response.statusCode(), response.body()); @@ -246,11 +257,11 @@ public Optional getInfo(Transaction transaction, PurchaseCon //@Override public boolean refund(Transaction transaction, PurchaseContext purchaseContext, Integer amount) { var configuration = loadConfiguration(purchaseContext); - var requestBody = new TransactionRefundBuilder(transaction.getPaymentId(), 0) - .addAuthentication(configuration.get(SAFERPAY_CUSTOMER_ID).getRequiredValue(), transaction.getReservationId()) - .build(Integer.toString(amount), transaction.getCurrency()); - var request = buildRequest(configuration, "/Payment/v1/Transaction/Refund", requestBody); try { + var requestBody = new TransactionRefundBuilder(transaction.getPaymentId(), 0) + .addAuthentication(configuration.get(SAFERPAY_CUSTOMER_ID).getRequiredValue(), transaction.getReservationId()) + .build(Integer.toString(amount), transaction.getCurrency()); + var request = buildRequest(configuration, "/Payment/v1/Transaction/Refund", requestBody); var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); if(!HttpUtils.callSuccessful(response)) { LOGGER.warn("Cannot refund transaction. Status {}, body {}", response.statusCode(), response.body()); @@ -277,11 +288,11 @@ private PaymentStatus retrievePaymentStatus(Map respons return responseBody.get("RedirectUrl").getAsString(); } - @AllArgsConstructor + private static class PaymentStatus { static final PaymentStatus EMPTY = new PaymentStatus(null, null, null, null); @@ -393,6 +403,13 @@ private static class PaymentStatus { private final String captureId; private final ZonedDateTime timestamp; + private PaymentStatus(PaymentResult paymentResult, String transactionId, String captureId, ZonedDateTime timestamp) { + this.paymentResult = paymentResult; + this.transactionId = transactionId; + this.captureId = captureId; + this.timestamp = timestamp; + } + private boolean isEmpty() { return paymentResult == null; diff --git a/src/main/java/alfio/manager/payment/StripeConnectManager.java b/src/main/java/alfio/manager/payment/StripeConnectManager.java index e1431134cf..3d866605bc 100644 --- a/src/main/java/alfio/manager/payment/StripeConnectManager.java +++ b/src/main/java/alfio/manager/payment/StripeConnectManager.java @@ -29,9 +29,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.builder.api.DefaultApi20; -import com.github.scribejava.core.model.OAuthConfig; import com.github.scribejava.core.oauth.OAuth20Service; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @@ -43,9 +43,10 @@ import static alfio.model.system.ConfigurationKeys.*; @Component -@Log4j2 public class StripeConnectManager implements OAuthPaymentProviderConnector { + private static final Logger log = LoggerFactory.getLogger(StripeConnectManager.class); + public static final String STRIPE_CONNECT_REDIRECT_PATH = "/admin/configuration/payment/stripe/authorize"; private final ExtensionManager extensionManager; private final ConfigurationManager configurationManager; @@ -64,12 +65,11 @@ public StripeConnectManager(ExtensionManager extensionManager, @Override public AuthorizationRequestDetails getConnectURL(int organizationId) { var options = configurationManager.getFor(Set.of(STRIPE_SECRET_KEY, STRIPE_CONNECT_CLIENT_ID, STRIPE_CONNECT_CALLBACK, BASE_URL), ConfigurationLevel.organization(organizationId)); - String secret = options.get(STRIPE_SECRET_KEY).getRequiredValue(); String clientId = options.get(STRIPE_CONNECT_CLIENT_ID).getRequiredValue(); String callbackURL = options.get(STRIPE_CONNECT_CALLBACK).getValueOrDefault(options.get(BASE_URL).getRequiredValue() + STRIPE_CONNECT_REDIRECT_PATH); String state = extensionManager.generateOAuth2StateParam(organizationId).orElse(UUID.randomUUID().toString()); - OAuthConfig config = new OAuthConfig(clientId, secret, callbackURL, "read_write", null, state, "code", null, null, null); - return new AuthorizationRequestDetails(new StripeConnectApi().getAuthorizationUrl(config, Collections.emptyMap()), state); + return new AuthorizationRequestDetails(new StripeConnectApi() + .getAuthorizationUrl("code", clientId, callbackURL, "read_write", state, Collections.emptyMap()), state); } @Override diff --git a/src/main/java/alfio/manager/payment/StripeCreditCardManager.java b/src/main/java/alfio/manager/payment/StripeCreditCardManager.java index c58752354f..77682383c9 100644 --- a/src/main/java/alfio/manager/payment/StripeCreditCardManager.java +++ b/src/main/java/alfio/manager/payment/StripeCreditCardManager.java @@ -34,8 +34,9 @@ import com.stripe.exception.StripeException; import com.stripe.model.BalanceTransaction; import com.stripe.model.Charge; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @@ -47,12 +48,13 @@ import static alfio.model.system.ConfigurationKeys.*; @Component -@Log4j2 public class StripeCreditCardManager implements PaymentProvider, ClientServerTokenRequest, RefundRequest, PaymentInfo { + private static final Logger log = LoggerFactory.getLogger(StripeCreditCardManager.class); + public static final String STRIPE_UNEXPECTED = "error.STEP2_STRIPE_unexpected"; private static final String STRIPE_MANAGER = StripeCreditCardManager.class.getName(); - public static final EnumSet OPTIONS_TO_LOAD = EnumSet.of(STRIPE_ENABLE_SCA, STRIPE_SECRET_KEY, STRIPE_PUBLIC_KEY); + protected static final EnumSet OPTIONS_TO_LOAD = EnumSet.of(STRIPE_ENABLE_SCA, STRIPE_SECRET_KEY, STRIPE_PUBLIC_KEY); private final TransactionRepository transactionRepository; private final BaseStripeManager baseStripeManager; @@ -151,7 +153,7 @@ public PaymentResult doPayment( PaymentSpecification spec ) { return optionalCharge.map(charge -> { log.info("transaction {} paid: {}", spec.getReservationId(), charge.getPaid()); Pair fees = Optional.ofNullable(charge.getBalanceTransactionObject()).map( bt -> { - List feeDetails = bt.getFeeDetails(); + List feeDetails = bt.getFeeDetails(); return Pair.of(Optional.ofNullable( BaseStripeManager.getFeeAmount(feeDetails, "application_fee")).map(Long::parseLong).orElse(0L), Optional.ofNullable( BaseStripeManager.getFeeAmount(feeDetails, "stripe_fee")).map(Long::parseLong).orElse(0L)); }).orElse(null); @@ -162,10 +164,9 @@ public PaymentResult doPayment( PaymentSpecification spec ) { fees != null ? fees.getLeft() : 0L, fees != null ? fees.getRight() : 0L, Transaction.Status.COMPLETE, Map.of(STRIPE_MANAGER_TYPE_KEY, STRIPE_MANAGER)); return PaymentResult.successful(charge.getId()); }).orElseGet(() -> PaymentResult.failed("error.STEP2_UNABLE_TO_TRANSITION")); + } catch (StripeException e) { + return PaymentResult.failed(baseStripeManager.handleException(e)); } catch (Exception e) { - if(e instanceof StripeException) { - return PaymentResult.failed( baseStripeManager.handleException((StripeException)e)); - } throw new IllegalStateException(e); } } diff --git a/src/main/java/alfio/manager/payment/StripeWebhookPaymentManager.java b/src/main/java/alfio/manager/payment/StripeWebhookPaymentManager.java index d790457ef4..e6bc105efa 100644 --- a/src/main/java/alfio/manager/payment/StripeWebhookPaymentManager.java +++ b/src/main/java/alfio/manager/payment/StripeWebhookPaymentManager.java @@ -36,13 +36,17 @@ import com.google.gson.JsonParser; import com.stripe.Stripe; import com.stripe.exception.StripeException; -import com.stripe.model.BalanceTransaction; import com.stripe.model.Charge; import com.stripe.model.PaymentIntent; import com.stripe.model.StripeObject; +import com.stripe.net.HttpHeaders; +import com.stripe.net.RequestOptions; +import com.stripe.net.StripeResponse; import com.stripe.net.Webhook; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -55,12 +59,14 @@ import static alfio.model.TicketReservation.TicketReservationStatus.EXTERNAL_PROCESSING_PAYMENT; import static alfio.model.TicketReservation.TicketReservationStatus.WAITING_EXTERNAL_CONFIRMATION; import static alfio.model.system.ConfigurationKeys.*; +import static java.util.Objects.requireNonNull; -@Log4j2 @Component @Transactional public class StripeWebhookPaymentManager implements PaymentProvider, RefundRequest, PaymentInfo, WebhookHandler, ClientServerTokenRequest, ServerInitiatedTransaction { + private static final Logger log = LoggerFactory.getLogger(StripeWebhookPaymentManager.class); + private static final String STRIPE_MANAGER = StripeWebhookPaymentManager.class.getName(); static final String CLIENT_SECRET_METADATA = "clientSecret"; private static final String PAYMENT_INTENT_SUCCEEDED = "payment_intent.succeeded"; @@ -78,6 +84,7 @@ public class StripeWebhookPaymentManager implements PaymentProvider, RefundReque private final List interestingEventTypes = List.of(PAYMENT_INTENT_SUCCEEDED, PAYMENT_INTENT_PAYMENT_FAILED, PAYMENT_INTENT_CREATED); private final Set cancellableStatuses = Set.of(REQUIRES_PAYMENT_METHOD, "requires_confirmation", "requires_action"); + @Autowired public StripeWebhookPaymentManager(ConfigurationManager configurationManager, TicketRepository ticketRepository, TransactionRepository transactionRepository, @@ -87,12 +94,28 @@ public StripeWebhookPaymentManager(ConfigurationManager configurationManager, AuditingRepository auditingRepository, Environment environment, ClockProvider clockProvider) { + this(configurationManager, + transactionRepository, + ticketReservationRepository, + eventRepository, + auditingRepository, + clockProvider, + new BaseStripeManager(configurationManager, configurationRepository, ticketRepository, environment)); + } + + StripeWebhookPaymentManager(ConfigurationManager configurationManager, + TransactionRepository transactionRepository, + TicketReservationRepository ticketReservationRepository, + EventRepository eventRepository, + AuditingRepository auditingRepository, + ClockProvider clockProvider, + BaseStripeManager baseStripeManager) { this.configurationManager = configurationManager; this.transactionRepository = transactionRepository; this.ticketReservationRepository = ticketReservationRepository; this.eventRepository = eventRepository; this.auditingRepository = auditingRepository; - this.baseStripeManager = new BaseStripeManager(configurationManager, configurationRepository, ticketRepository, environment); + this.baseStripeManager = baseStripeManager; this.clockProvider = clockProvider; } @@ -175,7 +198,7 @@ private TransactionInitializationToken buildTokenFromTransaction(Transaction tra if(status.equals("succeeded")) { // the existing PaymentIntent succeeded, so we can confirm the reservation log.info("marking reservation {} as paid, because PaymentIntent reports success", transaction.getReservationId()); - processSuccessfulPaymentIntent(transaction, paymentIntent, ticketReservationRepository.findReservationById(transaction.getReservationId()), purchaseContext); + processSuccessfulPaymentIntent(transaction, paymentIntent, ticketReservationRepository.findReservationById(transaction.getReservationId()), purchaseContext, requestOptions); return errorToken("Reservation status changed", true); } else if(!status.equals(REQUIRES_PAYMENT_METHOD)) { return errorToken("Payment in process", true); @@ -224,9 +247,11 @@ public Optional parseTransactionPayload(String body, var stripeEvent = Webhook.constructEvent(body, signature, getWebhookSignatureKey(paymentContext.getConfigurationLevel())); String eventType = stripeEvent.getType(); if(eventType.startsWith("charge.")) { - return deserializeObject(stripeEvent).map(obj -> new StripeChargeTransactionWebhookPayload(eventType, (Charge)obj)); + return deserializeObject(stripeEvent, body) + .map(obj -> new StripeChargeTransactionWebhookPayload(eventType, (Charge)obj)); } else if(eventType.startsWith("payment_intent.")) { - return deserializeObject(stripeEvent).map(obj -> new StripePaymentIntentWebhookPayload(eventType, (PaymentIntent)obj)); + return deserializeObject(stripeEvent, body) + .map(obj -> new StripePaymentIntentWebhookPayload(eventType, (PaymentIntent)obj)); } return Optional.empty(); } catch (Exception e) { @@ -235,7 +260,7 @@ public Optional parseTransactionPayload(String body, } } - private Optional deserializeObject(com.stripe.model.Event stripeEvent) { + private Optional deserializeObject(com.stripe.model.Event stripeEvent, String rawJson) { var dataObjectDeserializer = stripeEvent.getDataObjectDeserializer(); var cleanDeserialization = dataObjectDeserializer.getObject(); if(cleanDeserialization.isPresent()) { @@ -243,7 +268,17 @@ private Optional deserializeObject(com.stripe.model.Event stripeEv } log.warn("unable to deserialize payload. Expected version {}, actual {}, falling back to unsafe deserialization", Stripe.API_VERSION, stripeEvent.getApiVersion()); try { - return Optional.ofNullable(dataObjectDeserializer.deserializeUnsafe()); + return Optional.ofNullable(dataObjectDeserializer.deserializeUnsafe()) + .map(stripeObject -> { + // if the message we received was built with an API version older than 2022-11-15 + // we need to save the raw JSON body to ensure we have all the information to parse the message + // see https://stripe.com/docs/upgrades#2022-11-15 and https://github.com/alfio-event/alf.io/issues/1159 + if (stripeObject.getLastResponse() == null && "2022-11-15".compareTo(stripeEvent.getApiVersion()) > 0) { + log.debug("API version requires raw JSON body. Forcing 'lastResponse' property"); + stripeObject.setLastResponse(new StripeResponse(200, HttpHeaders.of(Map.of()), rawJson)); + } + return stripeObject; + }); } catch(Exception e) { throw new IllegalArgumentException("Cannot deserialize webhook event.", e); } @@ -277,20 +312,15 @@ public PaymentWebhookResult processWebhook(TransactionWebhookPayload payload, Tr } var reservation = optionalReservation.get(); var purchaseContext = paymentContext.getPurchaseContext(); - switch(payload.getType()) { - case PAYMENT_INTENT_CREATED: { - return PaymentWebhookResult.processStarted(buildTokenFromTransaction(transaction, purchaseContext, false)); - } - case PAYMENT_INTENT_SUCCEEDED: { - return processSuccessfulPaymentIntent(transaction, paymentIntent, reservation, purchaseContext); - } - case PAYMENT_INTENT_PAYMENT_FAILED: { - return processFailedPaymentIntent(transaction, reservation, purchaseContext); - } - default: - return PaymentWebhookResult.notRelevant("event is not relevant"); - } - + return switch (payload.getType()) { + case PAYMENT_INTENT_CREATED -> + PaymentWebhookResult.processStarted(buildTokenFromTransaction(transaction, purchaseContext, false)); + case PAYMENT_INTENT_SUCCEEDED -> + processSuccessfulPaymentIntent(transaction, paymentIntent, reservation, purchaseContext, baseStripeManager.options(purchaseContext).orElseThrow()); + case PAYMENT_INTENT_PAYMENT_FAILED -> + processFailedPaymentIntent(transaction, reservation, purchaseContext); + default -> PaymentWebhookResult.notRelevant("event is not relevant"); + }; } catch (Exception e) { log.error("Error while trying to confirm the reservation", e); return PaymentWebhookResult.error("unexpected error"); @@ -314,13 +344,16 @@ private PaymentWebhookResult processFailedPaymentIntent(Transaction transaction, return PaymentWebhookResult.failed("Charge has been reset by Stripe. This is usually caused by a rejection from the customer's bank"); } - private PaymentWebhookResult processSuccessfulPaymentIntent(Transaction transaction, PaymentIntent paymentIntent, TicketReservation reservation, PurchaseContext purchaseContext) { - var charge = paymentIntent.getCharges().getData().get(0); - var chargeId = charge.getId(); - long gtwFee = Optional.ofNullable(charge.getBalanceTransactionObject()).map(BalanceTransaction::getFee).orElse(0L); + private PaymentWebhookResult processSuccessfulPaymentIntent(Transaction transaction, + PaymentIntent paymentIntent, + TicketReservation reservation, + PurchaseContext purchaseContext, + RequestOptions requestOptions) throws StripeException { + var chargeAndFees = retrieveChargeIdAndFees(paymentIntent, requestOptions); + var chargeId = chargeAndFees.chargeId(); transactionRepository.lockByIdForUpdate(transaction.getId());// this serializes int affectedRows = transactionRepository.updateIfStatus(transaction.getId(), chargeId, - transaction.getPaymentId(), purchaseContext.now(clockProvider), transaction.getPlatformFee(), gtwFee, + transaction.getPaymentId(), purchaseContext.now(clockProvider), transaction.getPlatformFee(), chargeAndFees.getFeesOrZero(), Transaction.Status.COMPLETE, Map.of(), Transaction.Status.PENDING); List> modifications = List.of(Map.of("paymentId", chargeId, "paymentMethod", "stripe")); if(affectedRows == 0) { @@ -337,6 +370,38 @@ private PaymentWebhookResult processSuccessfulPaymentIntent(Transaction transact return PaymentWebhookResult.successful(new StripeSCACreditCardToken(transaction.getPaymentId(), chargeId, null)); } + private ChargeIdAndFees retrieveChargeIdAndFees(PaymentIntent paymentIntent, RequestOptions requestOptions) throws StripeException { + String chargeId = paymentIntent.getLatestCharge(); + String balanceTransactionId = null; + long fees = 0L; + if (chargeId == null) { + // compatibility mode for payloads with API version up to 2022-08-01 + var jsonObject = paymentIntent.getRawJsonObject(); + // old structure is paymentIntent -> data -> object -> charges -> data[0] -> id + var chargesContainer = requireNonNull(jsonObject.getAsJsonObject("data") + .getAsJsonObject("object") + .getAsJsonObject("charges"), "data -> object -> charges is null!"); + var latestCharge = requireNonNull(chargesContainer.getAsJsonArray("data").get(0), "charges is empty!") + .getAsJsonObject(); + + chargeId = requireNonNull(latestCharge.get("id"), "charges array is empty!").getAsString(); + if (latestCharge.has("balance_transaction")) { + balanceTransactionId = latestCharge.get("balance_transaction").getAsString(); + } + } + + if (balanceTransactionId == null) { + var charge = baseStripeManager.retrieveCharge(chargeId, requestOptions); + balanceTransactionId = charge.getBalanceTransaction(); + } + + if (balanceTransactionId != null) { + fees = baseStripeManager.retrieveBalanceTransaction(balanceTransactionId, requestOptions).getFee(); + } + + return new ChargeIdAndFees(chargeId, fees); + } + @Override public boolean accept(PaymentMethod paymentMethod, PaymentContext context, TransactionRequest transactionRequest) { return baseStripeManager.accept(paymentMethod, context, OPTIONS_TO_LOAD, this::isConfigurationValid); @@ -420,19 +485,14 @@ public PaymentWebhookResult forceTransactionCheck(TicketReservation reservation, PurchaseContext purchaseContext = paymentContext.getPurchaseContext(); var options = baseStripeManager.options(purchaseContext, builder -> builder.setIdempotencyKey(reservation.getId())).orElseThrow(); var intent = PaymentIntent.retrieve(transaction.getPaymentId(), options); - switch(intent.getStatus()) { - case "processing": - case "requires_action": - case "requires_confirmation": - return PaymentWebhookResult.pending(); - case "succeeded": - return processSuccessfulPaymentIntent(transaction, intent, reservation, purchaseContext); - case REQUIRES_PAYMENT_METHOD: + return switch (intent.getStatus()) { + case "processing", "requires_action", "requires_confirmation" -> PaymentWebhookResult.pending(); + case "succeeded" -> processSuccessfulPaymentIntent(transaction, intent, reservation, purchaseContext, options); + case REQUIRES_PAYMENT_METHOD -> //payment is failed. - return processFailedPaymentIntent(transaction, reservation, purchaseContext); - default: - return null; - } + processFailedPaymentIntent(transaction, reservation, purchaseContext); + default -> null; + }; } catch(Exception ex) { log.error("Error trying to check PaymentIntent status", ex); return PaymentWebhookResult.error("failed"); @@ -463,4 +523,10 @@ public Optional detectPaymentContext(String payload) { return Optional.empty(); } } + + private record ChargeIdAndFees(String chargeId, Long fees) { + public long getFeesOrZero() { + return fees != null ? fees : 0L; + } + } } diff --git a/src/main/java/alfio/manager/payment/saferpay/PaymentPageAssertRequestBuilder.java b/src/main/java/alfio/manager/payment/saferpay/PaymentPageAssertRequestBuilder.java index 58528101ec..83909ed1d1 100644 --- a/src/main/java/alfio/manager/payment/saferpay/PaymentPageAssertRequestBuilder.java +++ b/src/main/java/alfio/manager/payment/saferpay/PaymentPageAssertRequestBuilder.java @@ -17,12 +17,10 @@ package alfio.manager.payment.saferpay; import com.google.gson.stream.JsonWriter; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; +import java.io.IOException; import java.io.StringWriter; -@RequiredArgsConstructor public class PaymentPageAssertRequestBuilder { private String customerId; private String requestId; @@ -30,6 +28,11 @@ public class PaymentPageAssertRequestBuilder { private final String token; private final int retryIndicator; + public PaymentPageAssertRequestBuilder(String token, int retryIndicator) { + this.token = token; + this.retryIndicator = retryIndicator; + } + public PaymentPageAssertRequestBuilder addAuthentication(String customerId, String requestId) { this.customerId = customerId; this.requestId = requestId; @@ -37,8 +40,7 @@ public PaymentPageAssertRequestBuilder addAuthentication(String customerId, Stri } // @formatter:off - @SneakyThrows - public String build() { + public String build() throws IOException { var out = new StringWriter(); var requestHeaderBuilder = new RequestHeaderBuilder(customerId, requestId, retryIndicator); try (var writer = new JsonWriter(out)) { diff --git a/src/main/java/alfio/manager/payment/saferpay/PaymentPageInitializeRequestBuilder.java b/src/main/java/alfio/manager/payment/saferpay/PaymentPageInitializeRequestBuilder.java index 468b8e56a7..449ba719b9 100644 --- a/src/main/java/alfio/manager/payment/saferpay/PaymentPageInitializeRequestBuilder.java +++ b/src/main/java/alfio/manager/payment/saferpay/PaymentPageInitializeRequestBuilder.java @@ -19,10 +19,10 @@ import alfio.manager.payment.PaymentSpecification; import alfio.model.transaction.PaymentMethod; import com.google.gson.stream.JsonWriter; -import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.springframework.web.util.UriComponentsBuilder; +import java.io.IOException; import java.io.StringWriter; import java.util.Set; @@ -94,8 +94,7 @@ public PaymentPageInitializeRequestBuilder addOrderInformation(String orderId, return this; } - @SneakyThrows - public String build() { + public String build() throws IOException { var out = new StringWriter(); var requestHeaderBuilder = new RequestHeaderBuilder(customerId, requestId, retryIndicator); try (var writer = new JsonWriter(out)) { @@ -123,8 +122,7 @@ public String build() { return out.toString(); } - @SneakyThrows - private JsonWriter addPaymentMethods(JsonWriter writer) { + private JsonWriter addPaymentMethods(JsonWriter writer) throws IOException { var array = writer.name("PaymentMethods").beginArray(); for (String method : SUPPORTED_METHODS) { array.value(method); diff --git a/src/main/java/alfio/manager/payment/saferpay/RequestHeaderBuilder.java b/src/main/java/alfio/manager/payment/saferpay/RequestHeaderBuilder.java index faf3799c44..9098675ecf 100644 --- a/src/main/java/alfio/manager/payment/saferpay/RequestHeaderBuilder.java +++ b/src/main/java/alfio/manager/payment/saferpay/RequestHeaderBuilder.java @@ -17,23 +17,18 @@ package alfio.manager.payment.saferpay; import com.google.gson.stream.JsonWriter; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -@RequiredArgsConstructor -class RequestHeaderBuilder { +import java.io.IOException; + +record RequestHeaderBuilder(String customerId, String requestId, Integer retryIndicator) { private static final String SPEC_VERSION = "1.18"; - private final String customerId; - private final String requestId; - private final Integer retryIndicator; - @SneakyThrows - JsonWriter appendTo(JsonWriter writer) { + JsonWriter appendTo(JsonWriter writer) throws IOException { writer.name("RequestHeader").beginObject() // .name("SpecVersion").value(SPEC_VERSION) // .name("CustomerId").value(customerId) // .name("RequestId").value(requestId); - if(retryIndicator != null) { + if (retryIndicator != null) { writer.name("RetryIndicator").value(retryIndicator); } return writer.endObject(); diff --git a/src/main/java/alfio/manager/payment/saferpay/TransactionCaptureRequestBuilder.java b/src/main/java/alfio/manager/payment/saferpay/TransactionCaptureRequestBuilder.java index 2ceac4e6c6..b7a0132167 100644 --- a/src/main/java/alfio/manager/payment/saferpay/TransactionCaptureRequestBuilder.java +++ b/src/main/java/alfio/manager/payment/saferpay/TransactionCaptureRequestBuilder.java @@ -17,13 +17,10 @@ package alfio.manager.payment.saferpay; import com.google.gson.stream.JsonWriter; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import java.io.IOException; import java.io.StringWriter; -@RequiredArgsConstructor public class TransactionCaptureRequestBuilder { private final String token; @@ -31,14 +28,18 @@ public class TransactionCaptureRequestBuilder { private String customerId; private String requestId; + public TransactionCaptureRequestBuilder(String token, int retryIndicator) { + this.token = token; + this.retryIndicator = retryIndicator; + } + public TransactionCaptureRequestBuilder addAuthentication(String customerId, String requestId) { this.customerId = customerId; this.requestId = requestId; return this; } // @formatter:off - @SneakyThrows - public String build() { + public String build() throws IOException { return buildRequest(customerId, requestId, retryIndicator, token); } diff --git a/src/main/java/alfio/manager/payment/saferpay/TransactionInquireRequestBuilder.java b/src/main/java/alfio/manager/payment/saferpay/TransactionInquireRequestBuilder.java index fa196174aa..034dfa09c6 100644 --- a/src/main/java/alfio/manager/payment/saferpay/TransactionInquireRequestBuilder.java +++ b/src/main/java/alfio/manager/payment/saferpay/TransactionInquireRequestBuilder.java @@ -16,16 +16,19 @@ */ package alfio.manager.payment.saferpay; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; +import java.io.IOException; -@RequiredArgsConstructor public class TransactionInquireRequestBuilder { private final String transactionId; private final int retryIndicator; private String customerId; private String requestId; + public TransactionInquireRequestBuilder(String transactionId, int retryIndicator) { + this.transactionId = transactionId; + this.retryIndicator = retryIndicator; + } + public TransactionInquireRequestBuilder addAuthentication(String customerId, String requestId) { this.customerId = customerId; this.requestId = requestId; @@ -33,8 +36,7 @@ public TransactionInquireRequestBuilder addAuthentication(String customerId, Str } // @formatter:off - @SneakyThrows - public String build() { + public String build() throws IOException { return TransactionCaptureRequestBuilder.buildRequest(customerId, requestId, retryIndicator, transactionId); } } diff --git a/src/main/java/alfio/manager/payment/saferpay/TransactionRefundBuilder.java b/src/main/java/alfio/manager/payment/saferpay/TransactionRefundBuilder.java index d0c9e935b9..24be9bcd08 100644 --- a/src/main/java/alfio/manager/payment/saferpay/TransactionRefundBuilder.java +++ b/src/main/java/alfio/manager/payment/saferpay/TransactionRefundBuilder.java @@ -17,18 +17,21 @@ package alfio.manager.payment.saferpay; import com.google.gson.stream.JsonWriter; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; +import java.io.IOException; import java.io.StringWriter; -@RequiredArgsConstructor public class TransactionRefundBuilder { private final String captureId; private final int retryIndicator; private String customerId; private String requestId; + public TransactionRefundBuilder(String captureId, int retryIndicator) { + this.captureId = captureId; + this.retryIndicator = retryIndicator; + } + public TransactionRefundBuilder addAuthentication(String customerId, String requestId) { this.customerId = customerId; this.requestId = requestId; @@ -36,8 +39,7 @@ public TransactionRefundBuilder addAuthentication(String customerId, String requ } // @formatter:off - @SneakyThrows - public String build(String amountToRefund, String currencyCode) { + public String build(String amountToRefund, String currencyCode) throws IOException { var out = new StringWriter(); var requestHeaderBuilder = new RequestHeaderBuilder(customerId, requestId, retryIndicator); try (var writer = new JsonWriter(out)) { diff --git a/src/main/java/alfio/manager/support/AdditionalServiceInfo.java b/src/main/java/alfio/manager/support/AdditionalServiceInfo.java index 5280b59ea7..7c0cabaf99 100644 --- a/src/main/java/alfio/manager/support/AdditionalServiceInfo.java +++ b/src/main/java/alfio/manager/support/AdditionalServiceInfo.java @@ -18,14 +18,20 @@ import alfio.model.TicketFieldValueForAdditionalService; import lombok.Getter; -import lombok.RequiredArgsConstructor; import java.util.List; @Getter -@RequiredArgsConstructor public class AdditionalServiceInfo { private final String name; private final int count; private final List fields; + + public AdditionalServiceInfo(String name, + int count, + List fields) { + this.name = name; + this.count = count; + this.fields = fields; + } } diff --git a/src/main/java/alfio/manager/support/ConfirmationEmailConfiguration.java b/src/main/java/alfio/manager/support/ConfirmationEmailConfiguration.java index c4063f58b2..150258cf86 100644 --- a/src/main/java/alfio/manager/support/ConfirmationEmailConfiguration.java +++ b/src/main/java/alfio/manager/support/ConfirmationEmailConfiguration.java @@ -18,18 +18,26 @@ import alfio.manager.system.Mailer; import alfio.util.TemplateResource; -import lombok.AllArgsConstructor; import java.util.List; import java.util.Map; -@AllArgsConstructor public class ConfirmationEmailConfiguration { private final TemplateResource templateResource; private final String emailAddress; private final Map model; private final List attachments; + public ConfirmationEmailConfiguration(TemplateResource templateResource, + String emailAddress, + Map model, + List attachments) { + this.templateResource = templateResource; + this.emailAddress = emailAddress; + this.model = model; + this.attachments = attachments; + } + public TemplateResource getTemplateResource() { return templateResource; } diff --git a/src/main/java/alfio/manager/support/CustomMessageManager.java b/src/main/java/alfio/manager/support/CustomMessageManager.java index 6172bd9f9c..9a4d428841 100644 --- a/src/main/java/alfio/manager/support/CustomMessageManager.java +++ b/src/main/java/alfio/manager/support/CustomMessageManager.java @@ -25,18 +25,15 @@ import alfio.manager.system.Mailer; import alfio.model.*; import alfio.model.modification.MessageModification; +import alfio.model.system.ConfigurationKeys; import alfio.model.user.Organization; import alfio.repository.EventRepository; import alfio.repository.TicketCategoryRepository; import alfio.repository.TicketRepository; -import alfio.util.EventUtil; -import alfio.util.Json; -import alfio.util.RenderedTemplate; -import alfio.util.TemplateManager; +import alfio.util.*; import alfio.util.checkin.TicketCheckInUtil; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Triple; +import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; @@ -50,8 +47,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; @Component -@AllArgsConstructor -@Log4j2 public class CustomMessageManager { private final TemplateManager templateManager; @@ -66,6 +61,28 @@ public class CustomMessageManager { private final ExtensionManager extensionManager; private final EventRepository eventRepository; + public CustomMessageManager(TemplateManager templateManager, + EventManager eventManager, + TicketRepository ticketRepository, + TicketReservationManager ticketReservationManager, + NotificationManager notificationManager, + TicketCategoryRepository ticketCategoryRepository, + ConfigurationManager configurationManager, + MessageSourceManager messageSourceManager, + ExtensionManager extensionManager, + EventRepository eventRepository) { + this.templateManager = templateManager; + this.eventManager = eventManager; + this.ticketRepository = ticketRepository; + this.ticketReservationManager = ticketReservationManager; + this.notificationManager = notificationManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.configurationManager = configurationManager; + this.messageSourceManager = messageSourceManager; + this.extensionManager = extensionManager; + this.eventRepository = eventRepository; + } + public Map generatePreview(String eventName, Optional categoryId, List input, String username) { Map result = new HashMap<>(); Event event = eventManager.getSingleEvent(eventName, username); @@ -81,6 +98,11 @@ public void sendMessages(String eventName, Optional categoryId, List> byLanguage = input.stream().collect(Collectors.groupingBy(m -> m.getLocale().getLanguage())); var categoriesById = ticketCategoryRepository.findByEventIdAsMap(event.getId()); + var configuration = configurationManager.getFor(EnumSet.of(ConfigurationKeys.BASE_URL, + ConfigurationKeys.ENABLE_WALLET, ConfigurationKeys.ENABLE_PASS, ConfigurationKeys.ENABLE_HTML_EMAILS), event.getConfigurationLevel()); + var baseUrl = configuration.get(ConfigurationKeys.BASE_URL).getRequiredValue(); + boolean googleWalletEnabled = configuration.get(ConfigurationKeys.ENABLE_WALLET).getValueAsBooleanOrDefault(); + boolean appleWalletEnabled = configuration.get(ConfigurationKeys.ENABLE_PASS).getValueAsBooleanOrDefault(); sendMessagesExecutor.execute(() -> { var messageSource = messageSourceManager.getMessageSourceFor(event); @@ -97,8 +119,9 @@ public void sendMessages(String eventName, Optional categoryId, List { @@ -112,8 +135,9 @@ public void sendMessages(String eventName, Optional categoryId, List(TicketCheckInUtil.getOnlineCheckInInfo( extensionManager, eventRepository, @@ -133,10 +157,23 @@ public void sendMessages(String eventName, Optional categoryId, List RenderedTemplate.plaintext(text.toString(), templateModel), attachments); + templateModel.put("message", text); + templateModel.put("event", event); + templateModel.put("baseUrl", baseUrl); + notificationManager.sendSimpleEmail(event, ticket.getTicketsReservationId(), triple.getMiddle(), subject, + () -> templateManager.renderTemplate(event, TemplateResource.CUSTOM_MESSAGE, templateModel, Locale.forLanguageTag(ticket.getUserLanguage())), attachments); }); }); @@ -159,9 +196,16 @@ private List preview(Event event, List .collect(Collectors.toList()); } - public static Mailer.Attachment generateTicketAttachment(Ticket ticket, TicketReservation reservation, TicketCategory ticketCategory, Organization organization) { + public static Mailer.Attachment generateTicketAttachment(Ticket ticket, + TicketReservation reservation, + TicketCategory ticketCategory, + Organization organization, + boolean htmlEmailEnabled) { Map model = getModelForTicket(ticket, reservation, ticketCategory, organization); - return new Mailer.Attachment("ticket-" + ticket.getUuid() + ".pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.TICKET_PDF); + if (htmlEmailEnabled) { + model.put(Mailer.SKIP_PASSBOOK, "true"); + } + return new Mailer.Attachment("ticket-" + ticket.getUuid() + ".pdf", null, MediaType.APPLICATION_PDF_VALUE, model, Mailer.AttachmentIdentifier.TICKET_PDF); } private static Map getModelForTicket(Ticket ticket, TicketReservation reservation, TicketCategory ticketCategory, Organization organization) { diff --git a/src/main/java/alfio/manager/support/IncompatibleStateException.java b/src/main/java/alfio/manager/support/IncompatibleStateException.java new file mode 100644 index 0000000000..dd56b5e3bd --- /dev/null +++ b/src/main/java/alfio/manager/support/IncompatibleStateException.java @@ -0,0 +1,24 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support; + +public class IncompatibleStateException extends RuntimeException { + + public IncompatibleStateException(String message) { + super(message); + } +} diff --git a/src/main/java/alfio/manager/support/PaymentResult.java b/src/main/java/alfio/manager/support/PaymentResult.java index eb12e41c88..c727212db5 100644 --- a/src/main/java/alfio/manager/support/PaymentResult.java +++ b/src/main/java/alfio/manager/support/PaymentResult.java @@ -17,13 +17,11 @@ package alfio.manager.support; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import org.apache.commons.lang3.builder.ToStringBuilder; +import java.util.Objects; import java.util.Optional; -@EqualsAndHashCode -@ToString public final class PaymentResult { public enum Type { SUCCESSFUL, INITIALIZED, PENDING, REDIRECT, FAILED } @@ -103,4 +101,27 @@ public static PaymentResult initialized(String gatewayId) { public static PaymentResult failed( String errorCode) { return new PaymentResult(Type.FAILED).setErrorCode( errorCode ); } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("type", type) + .append("gatewayId", gatewayId) + .append("errorCode", errorCode) + .append("redirectUrl", redirectUrl) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PaymentResult that = (PaymentResult) o; + return type == that.type && Objects.equals(gatewayId, that.gatewayId) && Objects.equals(errorCode, that.errorCode) && Objects.equals(redirectUrl, that.redirectUrl); + } + + @Override + public int hashCode() { + return Objects.hash(type, gatewayId, errorCode, redirectUrl); + } } diff --git a/src/main/java/alfio/manager/support/PaymentWebhookResult.java b/src/main/java/alfio/manager/support/PaymentWebhookResult.java index d00dbe4f9f..17a7e1c3ea 100644 --- a/src/main/java/alfio/manager/support/PaymentWebhookResult.java +++ b/src/main/java/alfio/manager/support/PaymentWebhookResult.java @@ -17,10 +17,8 @@ package alfio.manager.support; import alfio.model.transaction.PaymentToken; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class PaymentWebhookResult { @@ -39,6 +37,13 @@ public enum Type { private final String reason; private final String redirectUrl; + public PaymentWebhookResult(Type type, PaymentToken paymentToken, String reason, String redirectUrl) { + this.type = type; + this.paymentToken = paymentToken; + this.reason = reason; + this.redirectUrl = redirectUrl; + } + public boolean isSuccessful() { return type == Type.SUCCESSFUL; } diff --git a/src/main/java/alfio/manager/support/RefundPriceContainer.java b/src/main/java/alfio/manager/support/RefundPriceContainer.java index 69c48e8c4b..b1015ea8fa 100644 --- a/src/main/java/alfio/manager/support/RefundPriceContainer.java +++ b/src/main/java/alfio/manager/support/RefundPriceContainer.java @@ -60,20 +60,12 @@ public VatStatus getVatStatus() { } private static VatStatus determineRefundVatStatus(VatStatus reservationVatStatus) { - switch (reservationVatStatus) { - case NOT_INCLUDED_NOT_CHARGED: - case INCLUDED_NOT_CHARGED: - return VatStatus.NOT_INCLUDED_NOT_CHARGED; - case NOT_INCLUDED_EXEMPT: - case INCLUDED_EXEMPT: - return VatStatus.NOT_INCLUDED_EXEMPT; - case INCLUDED: - case NOT_INCLUDED: - return VatStatus.INCLUDED; - case NONE: - return VatStatus.NONE; - default: - throw new IllegalStateException("Vat status "+reservationVatStatus+ " not mapped"); - } + return switch (reservationVatStatus) { + case NOT_INCLUDED_NOT_CHARGED, INCLUDED_NOT_CHARGED -> VatStatus.NOT_INCLUDED_NOT_CHARGED; + case NOT_INCLUDED_EXEMPT, INCLUDED_EXEMPT -> VatStatus.NOT_INCLUDED_EXEMPT; + case INCLUDED, NOT_INCLUDED -> VatStatus.INCLUDED; + case NONE -> VatStatus.NONE; + default -> throw new IllegalStateException("Vat status " + reservationVatStatus + " not mapped"); + }; } } diff --git a/src/main/java/alfio/manager/support/RetryFinalizeReservation.java b/src/main/java/alfio/manager/support/RetryFinalizeReservation.java new file mode 100644 index 0000000000..ffb5004d6a --- /dev/null +++ b/src/main/java/alfio/manager/support/RetryFinalizeReservation.java @@ -0,0 +1,99 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support; + +import alfio.model.TicketReservation.TicketReservationStatus; +import alfio.model.system.command.FinalizeReservation; +import alfio.model.transaction.PaymentProxy; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class RetryFinalizeReservation { + + private final String reservationId; + private final PaymentProxy paymentProxy; + private final boolean sendReservationConfirmationEmail; + private final boolean sendTickets; + private final String username; + private final boolean tcAccepted; + private final boolean privacyPolicyAccepted; + private final TicketReservationStatus originalStatus; + + @JsonCreator + public RetryFinalizeReservation(@JsonProperty("reservationId") String reservationId, + @JsonProperty("paymentProxy") PaymentProxy paymentProxy, + @JsonProperty("sendReservationConfirmationEmail") boolean sendReservationConfirmationEmail, + @JsonProperty("sendTickets") boolean sendTickets, + @JsonProperty("username") String username, + @JsonProperty("tcAccepted") boolean tcAccepted, + @JsonProperty("privacyPolicyAccepted") boolean privacyPolicyAccepted, + @JsonProperty("originalStatus") TicketReservationStatus originalStatus) { + this.reservationId = reservationId; + this.paymentProxy = paymentProxy; + this.sendReservationConfirmationEmail = sendReservationConfirmationEmail; + this.sendTickets = sendTickets; + this.username = username; + this.tcAccepted = tcAccepted; + this.privacyPolicyAccepted = privacyPolicyAccepted; + this.originalStatus = originalStatus; + } + + public String getReservationId() { + return reservationId; + } + + public PaymentProxy getPaymentProxy() { + return paymentProxy; + } + + public boolean isSendReservationConfirmationEmail() { + return sendReservationConfirmationEmail; + } + + public boolean isSendTickets() { + return sendTickets; + } + + public String getUsername() { + return username; + } + + public boolean isTcAccepted() { + return tcAccepted; + } + + public boolean isPrivacyPolicyAccepted() { + return privacyPolicyAccepted; + } + + public TicketReservationStatus getOriginalStatus() { + return originalStatus; + } + + public static RetryFinalizeReservation fromFinalizeReservation(FinalizeReservation finalizeReservation) { + var paymentSpecification = finalizeReservation.getPaymentSpecification(); + return new RetryFinalizeReservation(paymentSpecification.getReservationId(), + finalizeReservation.getPaymentProxy(), + finalizeReservation.isSendReservationConfirmationEmail(), + finalizeReservation.isSendTickets(), + finalizeReservation.getUsername(), + paymentSpecification.isTcAccepted(), + paymentSpecification.isPrivacyAccepted(), + finalizeReservation.getOriginalStatus() + ); + } +} diff --git a/src/main/java/alfio/manager/support/TemplateGenerator.java b/src/main/java/alfio/manager/support/TemplateGenerator.java index 680c793547..a0a256f89b 100644 --- a/src/main/java/alfio/manager/support/TemplateGenerator.java +++ b/src/main/java/alfio/manager/support/TemplateGenerator.java @@ -17,7 +17,7 @@ package alfio.manager.support; import alfio.util.RenderedTemplate; - +@FunctionalInterface public interface TemplateGenerator { RenderedTemplate generate(); } diff --git a/src/main/java/alfio/manager/support/extension/ExtensionEvent.java b/src/main/java/alfio/manager/support/extension/ExtensionEvent.java index 7d5e6d9585..c668fa83ef 100644 --- a/src/main/java/alfio/manager/support/extension/ExtensionEvent.java +++ b/src/main/java/alfio/manager/support/extension/ExtensionEvent.java @@ -29,6 +29,7 @@ public enum ExtensionEvent { CREDIT_NOTE_GENERATION, CREDIT_NOTE_GENERATED, TAX_ID_NUMBER_VALIDATION, + CUSTOM_TAX_POLICY_APPLICATION, RESERVATION_VALIDATION, EVENT_METADATA_UPDATE, // @@ -49,6 +50,8 @@ public enum ExtensionEvent { DYNAMIC_DISCOUNT_APPLICATION, + SUBSCRIPTION_ASSIGNED_GENERATE_METADATA, + ONLINE_CHECK_IN_REDIRECT, CUSTOM_ONLINE_JOIN_URL, diff --git a/src/main/java/alfio/manager/support/reservation/CannotProceedWithPayment.java b/src/main/java/alfio/manager/support/reservation/CannotProceedWithPayment.java new file mode 100644 index 0000000000..77cdf62fac --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/CannotProceedWithPayment.java @@ -0,0 +1,23 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +public class CannotProceedWithPayment extends RuntimeException { + public CannotProceedWithPayment(String message) { + super(message); + } +} diff --git a/src/main/java/alfio/manager/support/reservation/InvalidSpecialPriceTokenException.java b/src/main/java/alfio/manager/support/reservation/InvalidSpecialPriceTokenException.java new file mode 100644 index 0000000000..0a8cb122bb --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/InvalidSpecialPriceTokenException.java @@ -0,0 +1,21 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +public class InvalidSpecialPriceTokenException extends RuntimeException { + +} diff --git a/src/main/java/alfio/manager/support/reservation/MissingSpecialPriceTokenException.java b/src/main/java/alfio/manager/support/reservation/MissingSpecialPriceTokenException.java new file mode 100644 index 0000000000..b7af6448dd --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/MissingSpecialPriceTokenException.java @@ -0,0 +1,20 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +public class MissingSpecialPriceTokenException extends RuntimeException { +} diff --git a/src/main/java/alfio/manager/support/reservation/NotEnoughTicketsException.java b/src/main/java/alfio/manager/support/reservation/NotEnoughTicketsException.java new file mode 100644 index 0000000000..533c2d8e60 --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/NotEnoughTicketsException.java @@ -0,0 +1,21 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +public class NotEnoughTicketsException extends RuntimeException { + +} diff --git a/src/main/java/alfio/manager/support/reservation/OrderSummaryGenerator.java b/src/main/java/alfio/manager/support/reservation/OrderSummaryGenerator.java new file mode 100644 index 0000000000..c1b163e736 --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/OrderSummaryGenerator.java @@ -0,0 +1,312 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +import alfio.manager.PaymentManager; +import alfio.manager.i18n.MessageSourceManager; +import alfio.model.*; +import alfio.model.decorator.AdditionalServiceItemPriceContainer; +import alfio.model.decorator.TicketPriceContainer; +import alfio.model.subscription.Subscription; +import alfio.model.subscription.SubscriptionDescriptor; +import alfio.model.subscription.SubscriptionPriceContainer; +import alfio.model.transaction.PaymentProxy; +import alfio.repository.*; +import alfio.util.LocaleUtil; +import alfio.util.MonetaryUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static alfio.manager.support.reservation.ReservationCostCalculator.totalReservationCostWithVAT; +import static alfio.model.TicketReservation.TicketReservationStatus.DEFERRED_OFFLINE_PAYMENT; +import static alfio.util.MonetaryUtil.formatCents; +import static alfio.util.MonetaryUtil.formatUnit; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; + +@Component +public class OrderSummaryGenerator { + + private static final Logger log = LoggerFactory.getLogger(OrderSummaryGenerator.class); + private final TicketReservationRepository ticketReservationRepository; + private final AuditingRepository auditingRepository; + private final PaymentManager paymentManager; + private final TicketCategoryRepository ticketCategoryRepository; + private final AdditionalServiceTextRepository additionalServiceTextRepository; + private final SubscriptionRepository subscriptionRepository; + private final TicketRepository ticketRepository; + private final MessageSourceManager messageSourceManager; + private final ReservationCostCalculator reservationCostCalculator; + + public OrderSummaryGenerator(TicketReservationRepository ticketReservationRepository, + AuditingRepository auditingRepository, + PaymentManager paymentManager, + TicketCategoryRepository ticketCategoryRepository, + AdditionalServiceTextRepository additionalServiceTextRepository, + SubscriptionRepository subscriptionRepository, + TicketRepository ticketRepository, + MessageSourceManager messageSourceManager, + ReservationCostCalculator reservationCostCalculator) { + this.ticketReservationRepository = ticketReservationRepository; + this.auditingRepository = auditingRepository; + this.paymentManager = paymentManager; + this.ticketCategoryRepository = ticketCategoryRepository; + this.additionalServiceTextRepository = additionalServiceTextRepository; + this.subscriptionRepository = subscriptionRepository; + this.ticketRepository = ticketRepository; + this.messageSourceManager = messageSourceManager; + this.reservationCostCalculator = reservationCostCalculator; + } + + public OrderSummary orderSummaryForReservationId(String reservationId, PurchaseContext purchaseContext) { + TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId); + return orderSummaryForReservation(reservation, purchaseContext); + } + public OrderSummary orderSummaryForReservation(TicketReservation reservation, PurchaseContext context) { + var totalPriceAndDiscount = reservationCostCalculator.totalReservationCostWithVAT(reservation); + TotalPrice reservationCost = totalPriceAndDiscount.getLeft(); + PromoCodeDiscount discount = totalPriceAndDiscount.getRight().orElse(null); + // + boolean free = reservationCost.priceWithVAT() == 0; + String refundedAmount = null; + + boolean hasRefund = auditingRepository.countAuditsOfTypeForReservation(reservation.getId(), Audit.EventType.REFUND) > 0; + + if(hasRefund) { + refundedAmount = paymentManager.getInfo(reservation, context).paymentInformation().getRefundedAmount(); + } + + var currencyCode = reservation.getCurrencyCode(); + return new OrderSummary(reservationCost, + extractSummary(reservation.getId(), reservation.getVatStatus(), context, LocaleUtil.forLanguageTag(reservation.getUserLanguage()), discount, reservationCost), + free, + formatCents(reservationCost.priceWithVAT(), currencyCode), + formatCents(reservationCost.VAT(), currencyCode), + reservation.getStatus() == TicketReservation.TicketReservationStatus.OFFLINE_PAYMENT, + reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT, + reservation.getPaymentMethod() == PaymentProxy.ON_SITE, + Optional.ofNullable(context.getVat()).map(p -> MonetaryUtil.formatCents(MonetaryUtil.unitToCents(p, currencyCode), currencyCode)).orElse(null), + reservation.getVatStatus(), + refundedAmount); + } + + public OrderSummary orderSummaryForCreditNote(TicketReservation reservation, PurchaseContext purchaseContext, List removedTickets) { + var totalPriceAndDiscount = totalReservationCostWithVAT(null, purchaseContext, reservation, removedTickets, List.of(), List.of(), Optional.empty()); + TotalPrice reservationCost = totalPriceAndDiscount.getLeft(); + // + boolean free = reservationCost.priceWithVAT() == 0; + + var currencyCode = reservation.getCurrencyCode(); + return new OrderSummary(reservationCost, + extractSummary(reservation.getVatStatus(), purchaseContext, LocaleUtil.forLanguageTag(reservation.getUserLanguage()), null, reservationCost, removedTickets, Stream.empty(), subscriptionRepository.findSubscriptionsByReservationId(reservation.getId())), + free, + formatCents(reservationCost.priceWithVAT(), currencyCode), + formatCents(reservationCost.VAT(), currencyCode), + reservation.getStatus() == TicketReservation.TicketReservationStatus.OFFLINE_PAYMENT, + reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT, + reservation.getPaymentMethod() == PaymentProxy.ON_SITE, + Optional.ofNullable(purchaseContext.getVat()).map(p -> MonetaryUtil.formatCents(MonetaryUtil.unitToCents(p, currencyCode), currencyCode)).orElse(null), + reservation.getVatStatus(), + null); + } + + List extractSummary(PriceContainer.VatStatus reservationVatStatus, + PurchaseContext purchaseContext, + Locale locale, + PromoCodeDiscount promoCodeDiscount, + TotalPrice reservationCost, + List ticketsToInclude, + Stream>> additionalServicesToInclude, + List subscriptionsToInclude) { + log.trace("extract summary subscriptionsToInclude {}", subscriptionsToInclude); + List summary = new ArrayList<>(); + var currencyCode = reservationCost.currencyCode(); + List tickets = ticketsToInclude.stream() + .map(t -> TicketPriceContainer.from(t, reservationVatStatus, purchaseContext.getVat(), purchaseContext.getVatStatus(), promoCodeDiscount)).collect(toList()); + purchaseContext.event().ifPresent(event -> { + boolean multipleTaxRates = tickets.stream().map(TicketPriceContainer::getVatStatus).collect(Collectors.toSet()).size() > 1; + var ticketsByCategory = tickets.stream() + .collect(Collectors.groupingBy(TicketPriceContainer::getCategoryId)); + List>> sorted; + if (multipleTaxRates) { + sorted = ticketsByCategory + .entrySet() + .stream() + .sorted(Comparator.comparing((Map.Entry> e) -> e.getValue().get(0).getVatStatus()).reversed()) + .collect(Collectors.toList()); + } else { + sorted = new ArrayList<>(ticketsByCategory.entrySet()); + } + Map categoriesById; + + if(ticketsByCategory.isEmpty()) { + categoriesById = Map.of(); + } else { + categoriesById = ticketCategoryRepository.getByIdsAndActive(ticketsByCategory.keySet(), event.getId()) + .stream() + .collect(Collectors.toMap(TicketCategory::getId, Function.identity())); + } + + for (var categoryWithTickets : sorted) { + var categoryTickets = categoryWithTickets.getValue(); + final int subTotal = categoryTickets.stream().mapToInt(TicketPriceContainer::getSummarySrcPriceCts).sum(); + final int subTotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(categoryTickets); + var firstTicket = categoryTickets.get(0); + final int ticketPriceCts = firstTicket.getSummarySrcPriceCts(); + final int priceBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(firstTicket)); + String categoryName = categoriesById.get(categoryWithTickets.getKey()).getName(); + var ticketVatStatus = firstTicket.getVatStatus(); + summary.add(new SummaryRow(categoryName, formatCents(ticketPriceCts, currencyCode), formatCents(priceBeforeVat, currencyCode), categoryTickets.size(), formatCents(subTotal, currencyCode), formatCents(subTotalBeforeVat, currencyCode), subTotal, SummaryRow.SummaryType.TICKET, null, ticketVatStatus)); + if (PriceContainer.VatStatus.isVatExempt(ticketVatStatus) && ticketVatStatus != reservationVatStatus) { + summary.add(new SummaryRow(null, + "", + "", + 0, + formatCents(0, currencyCode, true), + formatCents(0, currencyCode, true), + 0, + SummaryRow.SummaryType.TAX_DETAIL, + "0", ticketVatStatus)); + } + } + }); + + summary.addAll(additionalServicesToInclude + .map(entry -> { + String language = locale.getLanguage(); + AdditionalServiceText title = additionalServiceTextRepository.findBestMatchByLocaleAndType(entry.getKey().getId(), language, AdditionalServiceText.TextType.TITLE); + if(!title.locale().equals(language) || title.id() == -1) { + log.debug("additional service {}: title not found for locale {}", title.additionalServiceId(), language); + } + List prices = generateASIPriceContainers(purchaseContext, null).apply(entry).collect(toList()); + AdditionalServiceItemPriceContainer first = prices.get(0); + final int subtotal = prices.stream().mapToInt(AdditionalServiceItemPriceContainer::getSrcPriceCts).sum(); + final int subtotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(prices); + return new SummaryRow(title.value(), formatCents(first.getSrcPriceCts(), currencyCode), formatCents(SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(first)), currencyCode), prices.size(), formatCents(subtotal, currencyCode), formatCents(subtotalBeforeVat, currencyCode), subtotal, SummaryRow.SummaryType.ADDITIONAL_SERVICE, null, first.getVatStatus()); + }).toList()); + + Optional.ofNullable(promoCodeDiscount).ifPresent(promo -> { + String formattedSingleAmount = "-" + (PromoCodeDiscount.DiscountType.isFixedAmount(promo.getDiscountType()) ? formatCents(promo.getDiscountAmount(), currencyCode) : (promo.getDiscountAmount()+"%")); + summary.add(new SummaryRow(formatPromoCode(promo, ticketsToInclude, locale, purchaseContext), + formattedSingleAmount, + formattedSingleAmount, + reservationCost.discountAppliedCount(), + formatCents(reservationCost.discount(), currencyCode), formatCents(reservationCost.discount(), currencyCode), reservationCost.discount(), + promo.isDynamic() ? SummaryRow.SummaryType.DYNAMIC_DISCOUNT : SummaryRow.SummaryType.PROMOTION_CODE, + null, reservationVatStatus)); + }); + // + if(purchaseContext instanceof SubscriptionDescriptor) { + if(!subscriptionsToInclude.isEmpty()) { + var subscription = subscriptionsToInclude.get(0); + var priceContainer = new SubscriptionPriceContainer(subscription, promoCodeDiscount, (SubscriptionDescriptor) purchaseContext); + var priceBeforeVat = formatUnit(priceContainer.getNetPrice(), currencyCode); + summary.add(new SummaryRow(purchaseContext.getTitle().get(locale.getLanguage()), + formatCents(priceContainer.getSummarySrcPriceCts(), currencyCode), + priceBeforeVat, + subscriptionsToInclude.size(), + formatCents(priceContainer.getSummarySrcPriceCts() * subscriptionsToInclude.size(), currencyCode), + formatUnit(priceContainer.getNetPrice().multiply(new BigDecimal(subscriptionsToInclude.size())), currencyCode), + priceContainer.getSummarySrcPriceCts(), + SummaryRow.SummaryType.SUBSCRIPTION, + null, + reservationVatStatus)); + } + } else if(CollectionUtils.isNotEmpty(subscriptionsToInclude)) { + log.trace("subscriptions to include is not empty"); + var subscription = subscriptionsToInclude.get(0); + subscriptionRepository.findOne(subscription.getSubscriptionDescriptorId(), subscription.getOrganizationId()).ifPresent(subscriptionDescriptor -> { + log.trace("found subscriptionDescriptor with ID {}", subscriptionDescriptor.getId()); + // find tickets with subscription applied + var ticketsSubscription = tickets.stream().filter(t -> Objects.equals(subscription.getId(), t.getSubscriptionId())).collect(toList()); + final int ticketPriceCts = ticketsSubscription.stream().mapToInt(TicketPriceContainer::getSummarySrcPriceCts).sum(); + final int priceBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(ticketsSubscription); + summary.add(new SummaryRow(subscriptionDescriptor.getLocalizedTitle(locale), + "-" + formatCents(ticketPriceCts, currencyCode), + "-" + formatCents(priceBeforeVat, currencyCode), + ticketsSubscription.size(), + "-" + formatCents(ticketPriceCts, currencyCode), + "-" + formatCents(priceBeforeVat, currencyCode), + ticketPriceCts, + SummaryRow.SummaryType.APPLIED_SUBSCRIPTION, + null, + reservationVatStatus)); + }); + } + + // + return summary; + } + + public List extractSummary(String reservationId, PriceContainer.VatStatus reservationVatStatus, + PurchaseContext purchaseContext, Locale locale, PromoCodeDiscount promoCodeDiscount, TotalPrice reservationCost) { + List subscriptionsToInclude; + if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.event)) { + subscriptionsToInclude = subscriptionRepository.findAppliedSubscriptionByReservationId(reservationId) + .map(List::of) + .orElse(List.of()); + } else { + subscriptionsToInclude = subscriptionRepository.findSubscriptionsByReservationId(reservationId); + } + + return extractSummary(reservationVatStatus, + purchaseContext, + locale, + promoCodeDiscount, + reservationCost, + ticketRepository.findTicketsInReservation(reservationId), + reservationCostCalculator.streamAdditionalServiceItems(reservationId, purchaseContext), + subscriptionsToInclude); + } + + private String formatPromoCode(PromoCodeDiscount promoCodeDiscount, List tickets, Locale locale, PurchaseContext purchaseContext) { + + if(promoCodeDiscount.getCodeType() == PromoCodeDiscount.CodeType.DYNAMIC) { + return messageSourceManager.getMessageSourceFor(purchaseContext).getMessage("reservation.dynamic.discount.description", null, locale); //we don't expose the internal promo code + } + + List filteredTickets = tickets.stream().filter(ticket -> promoCodeDiscount.getCategories().contains(ticket.getCategoryId())).toList(); + + if (promoCodeDiscount.getCategories().isEmpty() || filteredTickets.isEmpty()) { + return promoCodeDiscount.getPromoCode(); + } + + String formattedDiscountedCategories = filteredTickets.stream() + .map(Ticket::getCategoryId) + .collect(toSet()) + .stream() + .map(categoryId -> ticketCategoryRepository.getByIdAndActive(categoryId, promoCodeDiscount.getEventId()).getName()) + .collect(Collectors.joining(", ", "(", ")")); + + + return promoCodeDiscount.getPromoCode() + " " + formattedDiscountedCategories; + } + + private static Function>, Stream> generateASIPriceContainers(PurchaseContext purchaseContext, PromoCodeDiscount discount) { + return p -> p.getValue().stream().map(asi -> AdditionalServiceItemPriceContainer.from(asi, p.getKey(), purchaseContext, discount)); + } +} diff --git a/src/main/java/alfio/manager/support/reservation/ReservationAuditingHelper.java b/src/main/java/alfio/manager/support/reservation/ReservationAuditingHelper.java new file mode 100644 index 0000000000..31519040fb --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/ReservationAuditingHelper.java @@ -0,0 +1,75 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +import alfio.model.Audit; +import alfio.model.Ticket; +import alfio.model.metadata.TicketMetadataContainer; +import alfio.repository.AuditingRepository; +import alfio.util.ObjectDiffUtil; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static alfio.model.Audit.EntityType.TICKET; + +public class ReservationAuditingHelper { + + private final AuditingRepository auditingRepository; + + public ReservationAuditingHelper(AuditingRepository auditingRepository) { + this.auditingRepository = auditingRepository; + } + + public void auditUpdateMetadata(String reservationId, + int ticketId, + int eventId, + TicketMetadataContainer newMetadata, + TicketMetadataContainer oldMetadata) { + List> changes = ObjectDiffUtil.diff(oldMetadata, newMetadata, TicketMetadataContainer.class).stream() + .map(this::processChange) + .collect(Collectors.toList()); + + auditingRepository.insert(reservationId, null, eventId, Audit.EventType.UPDATE_TICKET_METADATA, new Date(), + TICKET, Integer.toString(ticketId), changes); + } + + public void auditUpdateTicket(Ticket preUpdateTicket, Map preUpdateTicketFields, Ticket postUpdateTicket, Map postUpdateTicketFields, int eventId) { + List diffTicket = ObjectDiffUtil.diff(preUpdateTicket, postUpdateTicket); + List diffTicketFields = ObjectDiffUtil.diff(preUpdateTicketFields, postUpdateTicketFields); + + List> changes = Stream.concat(diffTicket.stream(), diffTicketFields.stream()) + .map(this::processChange) + .collect(Collectors.toList()); + + auditingRepository.insert(preUpdateTicket.getTicketsReservationId(), null, eventId, + Audit.EventType.UPDATE_TICKET, new Date(), TICKET, Integer.toString(preUpdateTicket.getId()), changes); + } + + private HashMap processChange(ObjectDiffUtil.Change change) { + var v = new HashMap(); + v.put("propertyName", change.getPropertyName()); + v.put("state", change.getState()); + v.put("oldValue", change.getOldValue()); + v.put("newValue", change.getNewValue()); + return v; + } +} diff --git a/src/main/java/alfio/manager/support/reservation/ReservationCostCalculator.java b/src/main/java/alfio/manager/support/reservation/ReservationCostCalculator.java new file mode 100644 index 0000000000..62b1b9f72f --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/ReservationCostCalculator.java @@ -0,0 +1,126 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +import alfio.manager.PurchaseContextManager; +import alfio.model.*; +import alfio.model.decorator.TicketPriceContainer; +import alfio.model.subscription.Subscription; +import alfio.repository.*; +import alfio.util.MonetaryUtil; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static alfio.util.MonetaryUtil.unitToCents; +import static java.util.stream.Collectors.toList; + +@Component +public class ReservationCostCalculator { + + private final TicketReservationRepository ticketReservationRepository; + private final PurchaseContextManager purchaseContextManager; + private final PromoCodeDiscountRepository promoCodeDiscountRepository; + private final SubscriptionRepository subscriptionRepository; + private final TicketRepository ticketRepository; + private final AdditionalServiceRepository additionalServiceRepository; + private final AdditionalServiceItemRepository additionalServiceItemRepository; + + public ReservationCostCalculator(TicketReservationRepository ticketReservationRepository, + PurchaseContextManager purchaseContextManager, + PromoCodeDiscountRepository promoCodeDiscountRepository, + SubscriptionRepository subscriptionRepository, + TicketRepository ticketRepository, + AdditionalServiceRepository additionalServiceRepository, + AdditionalServiceItemRepository additionalServiceItemRepository) { + this.ticketReservationRepository = ticketReservationRepository; + this.purchaseContextManager = purchaseContextManager; + this.promoCodeDiscountRepository = promoCodeDiscountRepository; + + this.subscriptionRepository = subscriptionRepository; + this.ticketRepository = ticketRepository; + this.additionalServiceRepository = additionalServiceRepository; + this.additionalServiceItemRepository = additionalServiceItemRepository; + } + + /** + * Get the total cost with VAT if it's not included in the ticket price. + * + * @param reservationId + * @return + */ + public Pair> totalReservationCostWithVAT(String reservationId) { + return totalReservationCostWithVAT(ticketReservationRepository.findReservationById(reservationId)); + } + + public Pair> totalReservationCostWithVAT(TicketReservation reservation) { + return totalReservationCostWithVAT(purchaseContextManager.findByReservationId(reservation.getId()).orElseThrow(), reservation, ticketRepository.findTicketsInReservation(reservation.getId())); + } + + private Pair> totalReservationCostWithVAT(PurchaseContext purchaseContext, TicketReservation reservation, List tickets) { + var promoCodeDiscount = Optional.ofNullable(reservation.getPromoCodeDiscountId()).map(promoCodeDiscountRepository::findById); + var subscriptions = subscriptionRepository.findSubscriptionsByReservationId(reservation.getId()); + var appliedSubscription = subscriptionRepository.findAppliedSubscriptionByReservationId(reservation.getId()); + return totalReservationCostWithVAT(promoCodeDiscount.orElse(null), purchaseContext, reservation, tickets, + purchaseContext.event().map(event -> collectAdditionalServiceItems(reservation.getId(), event)).orElse(List.of()), + subscriptions, + appliedSubscription); + } + + public static Pair> totalReservationCostWithVAT(PromoCodeDiscount promoCodeDiscount, + PurchaseContext purchaseContext, + TicketReservation reservation, + List tickets, + List>> additionalServiceItems, + List subscriptions, + Optional appliedSubscription) { + + String currencyCode = purchaseContext.getCurrency(); + List ticketPrices = tickets.stream().map(t -> TicketPriceContainer.from(t, reservation.getVatStatus(), purchaseContext.getVat(), purchaseContext.getVatStatus(), promoCodeDiscount)).collect(toList()); + int discountedTickets = (int) ticketPrices.stream().filter(t -> t.getAppliedDiscount().compareTo(BigDecimal.ZERO) > 0).count(); + int discountAppliedCount = discountedTickets <= 1 || promoCodeDiscount.getDiscountType() == PromoCodeDiscount.DiscountType.FIXED_AMOUNT ? discountedTickets : 1; + if(discountAppliedCount == 0 && promoCodeDiscount != null && promoCodeDiscount.getDiscountType() == PromoCodeDiscount.DiscountType.FIXED_AMOUNT_RESERVATION) { + discountAppliedCount = 1; + } + var reservationPriceCalculator = alfio.manager.system.ReservationPriceCalculator.from(reservation, promoCodeDiscount, tickets, purchaseContext, additionalServiceItems, subscriptions, appliedSubscription); + var price = new TotalPrice(unitToCents(reservationPriceCalculator.getFinalPrice(), currencyCode), + unitToCents(reservationPriceCalculator.getVAT(), currencyCode), + -MonetaryUtil.unitToCents(reservationPriceCalculator.getAppliedDiscount(), currencyCode), + discountAppliedCount, + currencyCode); + return Pair.of(price, Optional.ofNullable(promoCodeDiscount)); + } + + Stream>> streamAdditionalServiceItems(String reservationId, PurchaseContext purchaseContext) { + return purchaseContext.event().map(event -> { + return additionalServiceItemRepository.findByReservationUuid(reservationId) + .stream() + .collect(Collectors.groupingBy(AdditionalServiceItem::getAdditionalServiceId)) + .entrySet() + .stream() + .map(entry -> Pair.of(additionalServiceRepository.getById(entry.getKey(), event.getId()), entry.getValue())); + }).orElse(Stream.empty()); + } + public List>> collectAdditionalServiceItems(String reservationId, Event event) { + return streamAdditionalServiceItems(reservationId, event).collect(Collectors.toList()); + } +} diff --git a/src/main/java/alfio/manager/support/reservation/ReservationEmailContentHelper.java b/src/main/java/alfio/manager/support/reservation/ReservationEmailContentHelper.java new file mode 100644 index 0000000000..860e2b89b3 --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/ReservationEmailContentHelper.java @@ -0,0 +1,341 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +import alfio.controller.support.TemplateProcessor; +import alfio.manager.BillingDocumentManager; +import alfio.manager.ExtensionManager; +import alfio.manager.NotificationManager; +import alfio.manager.i18n.MessageSourceManager; +import alfio.manager.support.ConfirmationEmailConfiguration; +import alfio.manager.support.IncompatibleStateException; +import alfio.manager.support.PartialTicketTextGenerator; +import alfio.manager.system.ConfigurationLevel; +import alfio.manager.system.ConfigurationManager; +import alfio.manager.system.Mailer; +import alfio.model.*; +import alfio.model.extension.CustomEmailText; +import alfio.model.metadata.SubscriptionMetadata; +import alfio.model.subscription.Subscription; +import alfio.model.subscription.UsageDetails; +import alfio.model.system.ConfigurationKeys; +import alfio.model.user.Organization; +import alfio.repository.*; +import alfio.repository.user.OrganizationRepository; +import alfio.util.*; +import alfio.util.checkin.TicketCheckInUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.*; + +import static alfio.model.BillingDocument.Type.INVOICE; +import static alfio.model.BillingDocument.Type.RECEIPT; +import static alfio.model.system.ConfigurationKeys.*; +import static alfio.util.ReservationUtil.reservationUrl; +import static java.util.stream.Collectors.*; +import static org.springframework.http.MediaType.APPLICATION_PDF; + +@Component +public class ReservationEmailContentHelper { + + private static final String RESERVATION_ID = "reservationId"; + private final ConfigurationManager configurationManager; + private final NotificationManager notificationManager; + private final SubscriptionRepository subscriptionRepository; + private final MessageSourceManager messageSourceManager; + private final OrderSummaryGenerator orderSummaryGenerator; + private final TicketReservationRepository ticketReservationRepository; + private final TicketCategoryRepository ticketCategoryRepository; + private final TicketFieldRepository ticketFieldRepository; + private final OrganizationRepository organizationRepository; + private final TicketRepository ticketRepository; + private final TemplateManager templateManager; + private final BillingDocumentManager billingDocumentManager; + private final ExtensionManager extensionManager; + private final EventRepository eventRepository; + + + public ReservationEmailContentHelper(ConfigurationManager configurationManager, + NotificationManager notificationManager, + SubscriptionRepository subscriptionRepository, + MessageSourceManager messageSourceManager, + OrderSummaryGenerator orderSummaryGenerator, + TicketReservationRepository ticketReservationRepository, + TicketCategoryRepository ticketCategoryRepository, + TicketFieldRepository ticketFieldRepository, + OrganizationRepository organizationRepository, + TicketRepository ticketRepository, + TemplateManager templateManager, + BillingDocumentManager billingDocumentManager, + ExtensionManager extensionManager, + EventRepository eventRepository) { + this.configurationManager = configurationManager; + this.notificationManager = notificationManager; + this.subscriptionRepository = subscriptionRepository; + this.messageSourceManager = messageSourceManager; + this.orderSummaryGenerator = orderSummaryGenerator; + this.ticketReservationRepository = ticketReservationRepository; + this.ticketCategoryRepository = ticketCategoryRepository; + this.ticketFieldRepository = ticketFieldRepository; + this.organizationRepository = organizationRepository; + this.ticketRepository = ticketRepository; + this.templateManager = templateManager; + this.billingDocumentManager = billingDocumentManager; + this.extensionManager = extensionManager; + this.eventRepository = eventRepository; + } + + + public void sendConfirmationEmail(PurchaseContext purchaseContext, TicketReservation ticketReservation, Locale language, String username) { + String reservationId = ticketReservation.getId(); + checkIfFinalized(reservationId); + OrderSummary summary = orderSummaryGenerator.orderSummaryForReservationId(reservationId, purchaseContext); + + List attachments; + if (configurationManager.canAttachBillingDocumentToConfirmationEmail(purchaseContext)) { // https://github.com/alfio-event/alf.io/issues/573 + attachments = generateAttachmentForConfirmationEmail(purchaseContext, ticketReservation, language, summary, username); + } else{ + attachments = List.of(); + } + var vat = getVAT(purchaseContext); + + List configurations = new ArrayList<>(); + if(purchaseContext.ofType(PurchaseContext.PurchaseContextType.subscription)) { + var firstSubscription = subscriptionRepository.findSubscriptionsByReservationId(reservationId).stream().findFirst().orElseThrow(); + boolean sendSeparateEmailToOwner = !Objects.equals(firstSubscription.getEmail(), ticketReservation.getEmail()); + var metadata = Objects.requireNonNullElseGet(subscriptionRepository.getSubscriptionMetadata(firstSubscription.getId()), SubscriptionMetadata::empty); + Map initialModel = Map.of( + "pin", firstSubscription.getPin(), + "subscriptionId", firstSubscription.getId(), + "includePin", metadata.getConfiguration().isDisplayPin(), + "fullName", firstSubscription.getFirstName() + " " + firstSubscription.getLastName()); + var model = prepareModelForReservationEmail(purchaseContext, ticketReservation, vat, summary, List.of(), initialModel); + var subscriptionAttachments = new ArrayList<>(attachments); + subscriptionAttachments.add(generateSubscriptionAttachment(firstSubscription)); + configurations.add(new ConfirmationEmailConfiguration(TemplateResource.CONFIRMATION_EMAIL_SUBSCRIPTION, firstSubscription.getEmail(), model, sendSeparateEmailToOwner ? List.of() : subscriptionAttachments)); + if(sendSeparateEmailToOwner) { + var separateModel = new HashMap<>(model); + separateModel.put("includePin", false); + separateModel.put("fullName", ticketReservation.getFullName()); + configurations.add(new ConfirmationEmailConfiguration(TemplateResource.CONFIRMATION_EMAIL_SUBSCRIPTION, ticketReservation.getEmail(), separateModel, subscriptionAttachments)); + } + } else { + var model = prepareModelForReservationEmail(purchaseContext, ticketReservation, vat, summary, ticketRepository.findTicketsInReservation(ticketReservation.getId()), Map.of()); + configurations.add(new ConfirmationEmailConfiguration(TemplateResource.CONFIRMATION_EMAIL, ticketReservation.getEmail(), model, attachments)); + } + + var messageSource = messageSourceManager.getMessageSourceFor(purchaseContext); + var localizedType = messageSource.getMessage("purchase-context."+purchaseContext.getType(), null, language); + configurations.forEach(configuration -> { + notificationManager.sendSimpleEmail(purchaseContext, ticketReservation.getId(), configuration.getEmailAddress(), messageSource.getMessage("reservation-email-subject", + new Object[]{ configurationManager.getShortReservationID(purchaseContext, ticketReservation), purchaseContext.getTitle().get(language.getLanguage()), localizedType}, language), + () -> templateManager.renderTemplate(purchaseContext, configuration.getTemplateResource(), configuration.getModel(), language), + configuration.getAttachments()); + }); + } + + private Mailer.Attachment generateSubscriptionAttachment(Subscription subscription) { + var model = new HashMap(); + model.put("subscriptionId", subscription.getId().toString()); + return new Mailer.Attachment("subscription_" + subscription.getId() + ".pdf", null, APPLICATION_PDF.toString(), model, Mailer.AttachmentIdentifier.SUBSCRIPTION_PDF); + } + + private List generateAttachmentForConfirmationEmail(PurchaseContext purchaseContext, + TicketReservation ticketReservation, + Locale language, + OrderSummary summary, + String username) { + if(mustGenerateBillingDocument(summary, ticketReservation)) { //#459 - include PDF invoice in reservation email + BillingDocument.Type type = ticketReservation.getHasInvoiceNumber() ? INVOICE : RECEIPT; + return billingDocumentManager.generateBillingDocumentAttachment(purchaseContext, ticketReservation, language, type, username, summary); + } + return List.of(); + } + + public void sendReservationCompleteEmailToOrganizer(PurchaseContext purchaseContext, TicketReservation ticketReservation, Locale language, String username) { + String reservationId = ticketReservation.getId(); + + checkIfFinalized(reservationId); + + Organization organization = organizationRepository.getById(purchaseContext.getOrganizationId()); + List cc = notificationManager.getCCForEventOrganizer(purchaseContext); + + Map reservationEmailModel = prepareModelForReservationEmail(purchaseContext, ticketReservation); + + OrderSummary summary = orderSummaryGenerator.orderSummaryForReservationId(reservationId, purchaseContext); + + List attachments = Collections.emptyList(); + + if (!configurationManager.canGenerateReceiptOrInvoiceToCustomer(purchaseContext) || configurationManager.isInvoiceOnly(purchaseContext)) { // https://github.com/alfio-event/alf.io/issues/573 + attachments = generateAttachmentForConfirmationEmail(purchaseContext, ticketReservation, language, summary, username); + } + + + String shortReservationID = configurationManager.getShortReservationID(purchaseContext, ticketReservation); + notificationManager.sendSimpleEmail(purchaseContext, null, organization.getEmail(), cc, "Reservation complete " + shortReservationID, + () -> templateManager.renderTemplate(purchaseContext, TemplateResource.CONFIRMATION_EMAIL_FOR_ORGANIZER, reservationEmailModel, language), + attachments); + } + + private static boolean mustGenerateBillingDocument(OrderSummary summary, TicketReservation ticketReservation) { + return !summary.getFree() && (!summary.getNotYetPaid() || (summary.getWaitingForPayment() && ticketReservation.isInvoiceRequested())); + } + + public List generateBillingDocumentAttachment(PurchaseContext purchaseContext, + TicketReservation ticketReservation, + Locale language, + Map billingDocumentModel, + BillingDocument.Type documentType) { + Map model = new HashMap<>(); + model.put(RESERVATION_ID, ticketReservation.getId()); + purchaseContext.event().ifPresent(event -> model.put("eventId", Integer.toString(event.getId()))); + model.put("language", Json.toJson(language)); + model.put("reservationEmailModel", Json.toJson(billingDocumentModel));//ticketReservation.getHasInvoiceNumber() + switch (documentType) { + case INVOICE: + return Collections.singletonList(new Mailer.Attachment("invoice.pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.INVOICE_PDF)); + case RECEIPT: + return Collections.singletonList(new Mailer.Attachment("receipt.pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.RECEIPT_PDF)); + case CREDIT_NOTE: + return Collections.singletonList(new Mailer.Attachment("credit-note.pdf", null, "application/pdf", model, Mailer.AttachmentIdentifier.CREDIT_NOTE_PDF)); + default: + throw new IllegalStateException(documentType+" is not supported"); + } + } + + public String getReservationEmailSubject(PurchaseContext purchaseContext, Locale reservationLanguage, String key, String id) { + return messageSourceManager.getMessageSourceFor(purchaseContext) + .getMessage(key, new Object[]{id, purchaseContext.getDisplayName()}, reservationLanguage); + } + + public Map prepareModelForReservationEmail(PurchaseContext purchaseContext, + TicketReservation reservation, + Optional vat, + OrderSummary summary, + List ticketsToInclude, + Map initialOptions) { + Organization organization = organizationRepository.getById(purchaseContext.getOrganizationId()); + String baseUrl = configurationManager.baseUrl(purchaseContext); + var reservationId = reservation.getId(); + String reservationUrl = reservationUrl(reservation, purchaseContext, configurationManager); + String reservationShortID = configurationManager.getShortReservationID(purchaseContext, reservation); + + var bankingInfo = configurationManager.getFor(Set.of(INVOICE_ADDRESS, BANK_ACCOUNT_NR, BANK_ACCOUNT_OWNER), ConfigurationLevel.purchaseContext(purchaseContext)); + Optional invoiceAddress = bankingInfo.get(INVOICE_ADDRESS).getValue(); + Optional bankAccountNr = bankingInfo.get(BANK_ACCOUNT_NR).getValue(); + Optional bankAccountOwner = bankingInfo.get(BANK_ACCOUNT_OWNER).getValue(); + + Map> ticketsByCategory = ticketsToInclude + .stream() + .collect(groupingBy(Ticket::getCategoryId)); + final List ticketsWithCategory = ReservationUtil.collectTicketsWithCategory(ticketsByCategory, ticketCategoryRepository); + Map baseModel = new HashMap<>(); + baseModel.putAll(initialOptions); + baseModel.putAll(extensionManager.handleReservationEmailCustomText(purchaseContext, reservation, ticketReservationRepository.getAdditionalInfo(reservationId)) + .map(CustomEmailText::toMap) + .orElse(Map.of())); + Map model = TemplateResource.prepareModelForConfirmationEmail(organization, purchaseContext, reservation, vat, ticketsWithCategory, summary, baseUrl, reservationUrl, reservationShortID, invoiceAddress, bankAccountNr, bankAccountOwner, baseModel); + boolean euBusiness = StringUtils.isNotBlank(reservation.getVatCountryCode()) && StringUtils.isNotBlank(reservation.getVatNr()) + && configurationManager.getForSystem(ConfigurationKeys.EU_COUNTRIES_LIST).getRequiredValue().contains(reservation.getVatCountryCode()) + && PriceContainer.VatStatus.isVatExempt(reservation.getVatStatus()); + model.put("euBusiness", euBusiness); + model.put("publicId", configurationManager.getPublicReservationID(purchaseContext, reservation)); + model.put("invoicingAdditionalInfo", ticketReservationRepository.getAdditionalInfo(reservationId).getInvoicingAdditionalInfo()); + if(purchaseContext.getType() == PurchaseContext.PurchaseContextType.event) { + var event = purchaseContext.event().orElseThrow(); + model.put("displayLocation", ticketsWithCategory.stream() + .noneMatch(tc -> EventUtil.isAccessOnline(tc.getCategory(), event))); + } else { + model.put("displayLocation", false); + } + if(ticketReservationRepository.hasSubscriptionApplied(reservationId)) { + model.put("displaySubscriptionUsage", true); + var subscription = subscriptionRepository.findAppliedSubscriptionByReservationId(reservationId).orElseThrow(); + if(subscription.getMaxEntries() > -1) { + var subscriptionUsageDetails = UsageDetails.fromSubscription(subscription, ticketRepository.countSubscriptionUsage(subscription.getId(), null)); + model.put("subscriptionUsageDetails", subscriptionUsageDetails); + model.put("subscriptionUrl", reservationUrl(reservation, purchaseContext, configurationManager)); + } + } + return model; + } + + public void sendTicketByEmail(Ticket ticket, Locale locale, Event event, PartialTicketTextGenerator confirmationTextBuilder) { + TicketReservation reservation = ticketReservationRepository.findReservationById(ticket.getTicketsReservationId()); + checkIfFinalized(reservation.getId()); + TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(ticket.getCategoryId(), event.getId()); + notificationManager.sendTicketByEmail(ticket, event, locale, confirmationTextBuilder, reservation, ticketCategory, () -> retrieveAttendeeAdditionalInfoForTicket(ticket)); + } + + private void checkIfFinalized(String reservationId) { + if (!Boolean.TRUE.equals(ticketReservationRepository.checkIfFinalized(reservationId))) { + throw new IncompatibleStateException("Reservation was confirmed but not finalized yet. Cannot send emails."); + } + } + + public Map> retrieveAttendeeAdditionalInfoForTicket(Ticket ticket) { + return ticketFieldRepository.findNameAndValue(ticket.getId()) + .stream() + .collect(groupingBy(FieldNameAndValue::getName, mapping(FieldNameAndValue::getValue, toList()))); + } + + public PartialTicketTextGenerator getTicketEmailGenerator(Event event, + TicketReservation ticketReservation, + Locale ticketLanguage, + Map> additionalInfo) { + return ticket -> { + Organization organization = organizationRepository.getById(event.getOrganizationId()); + String ticketUrl = ReservationUtil.ticketUpdateUrl(event, ticket, configurationManager); + var ticketCategory = ticketCategoryRepository.getById(ticket.getCategoryId()); + + var initialModel = new HashMap<>(extensionManager.handleTicketEmailCustomText(event, ticketReservation, ticketReservationRepository.getAdditionalInfo(ticketReservation.getId()), ticketFieldRepository.findAllByTicketId(ticket.getId())) + .map(CustomEmailText::toMap) + .orElse(Map.of())); + if(EventUtil.isAccessOnline(ticketCategory, event)) { + initialModel.putAll(TicketCheckInUtil.getOnlineCheckInInfo( + extensionManager, + eventRepository, + ticketCategoryRepository, + configurationManager, + event, + ticketLanguage, + ticket, + ticketCategory, + additionalInfo + )); + } + var baseUrl = StringUtils.removeEnd(configurationManager.getFor(BASE_URL, ConfigurationLevel.event(event)).getRequiredValue(), "/"); + var calendarUrl = UriComponentsBuilder.fromUriString(baseUrl + "/api/v2/public/event/{eventShortName}/calendar/{currentLang}") + .queryParam("type", "google") + .build(Map.of("eventShortName", event.getShortName(), "currentLang", ticketLanguage.getLanguage())) + .toString(); + return TemplateProcessor.buildPartialEmail(event, organization, ticketReservation, ticketCategory, templateManager, baseUrl, ticketUrl, calendarUrl, ticketLanguage, initialModel).generate(ticket); + }; + } + + public Optional getVAT(PurchaseContext purchaseContext) { + return configurationManager.getFor(VAT_NR, purchaseContext.getConfigurationLevel()).getValue(); + } + + public Map prepareModelForReservationEmail(PurchaseContext purchaseContext, TicketReservation reservation) { + Optional vat = getVAT(purchaseContext); + OrderSummary summary = orderSummaryGenerator.orderSummaryForReservationId(reservation.getId(), purchaseContext); + return prepareModelForReservationEmail(purchaseContext, reservation, vat, summary, ticketRepository.findTicketsInReservation(reservation.getId()), Map.of()); + } +} diff --git a/src/main/java/alfio/manager/support/reservation/TooManyTicketsForDiscountCodeException.java b/src/main/java/alfio/manager/support/reservation/TooManyTicketsForDiscountCodeException.java new file mode 100644 index 0000000000..8c84a7f297 --- /dev/null +++ b/src/main/java/alfio/manager/support/reservation/TooManyTicketsForDiscountCodeException.java @@ -0,0 +1,20 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.support.reservation; + +public class TooManyTicketsForDiscountCodeException extends RuntimeException { +} diff --git a/src/main/java/alfio/manager/support/response/ValidatedResponse.java b/src/main/java/alfio/manager/support/response/ValidatedResponse.java index 39a527b72d..306520fa9e 100644 --- a/src/main/java/alfio/manager/support/response/ValidatedResponse.java +++ b/src/main/java/alfio/manager/support/response/ValidatedResponse.java @@ -20,34 +20,34 @@ import alfio.model.result.Result; import alfio.model.result.ValidationResult; import alfio.model.result.WarningMessage; -import lombok.AllArgsConstructor; -import lombok.Getter; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -@AllArgsConstructor public class ValidatedResponse { private final ValidationResult validationResult; private final T value; + public ValidatedResponse(ValidationResult validationResult, T value) { + this.validationResult = validationResult; + this.value = value; + } + public static ValidatedResponse toResponse(BindingResult bindingResult, T value) { var transformed = bindingResult.getAllErrors().stream().map(objectError -> { - if (objectError instanceof FieldError) { - var fe = (FieldError) objectError; + if (objectError instanceof FieldError fe) { return new ValidationResult.ErrorDescriptor(fe.getField(), "", fe.getCode(), fe.getArguments()); } else { return new ValidationResult.ErrorDescriptor(objectError.getObjectName(), "", objectError.getCode(), objectError.getArguments()); } - }).collect(Collectors.toList()); + }).toList(); - List warnings = bindingResult instanceof CustomBindingResult ? ((CustomBindingResult)bindingResult).getWarnings() : List.of(); + List warnings = bindingResult instanceof CustomBindingResult cbd ? cbd.getWarnings() : List.of(); return new ValidatedResponse<>(ValidationResult.failed(transformed, warnings), value); } @@ -57,7 +57,7 @@ public static ValidatedResponse fromResult(Result result, String objec } var transformed = result.getErrors().stream() .map(ec -> new ValidationResult.ErrorDescriptor(objectName, "", ec.getCode())) - .collect(Collectors.toList()); + .toList(); return new ValidatedResponse<>(ValidationResult.failed(transformed), null); } @@ -73,7 +73,7 @@ public boolean isSuccess() { public List getValidationErrors() { return validationResult.getValidationErrors().stream() .map(ed -> new ErrorDescriptor(ed.getFieldName(), ed.getCode(), fromArray(ed.getArguments()))) - .collect(Collectors.toList()); + .toList(); } public int getErrorCount() { @@ -101,11 +101,28 @@ private static Map fromArray(Object[] arguments) { } } - @AllArgsConstructor - @Getter + public static class ErrorDescriptor { private final String fieldName; private final String code; private final Map arguments; + + public String getFieldName() { + return fieldName; + } + + public String getCode() { + return code; + } + + public Map getArguments() { + return arguments; + } + + public ErrorDescriptor(String fieldName, String code, Map arguments) { + this.fieldName = fieldName; + this.code = code; + this.arguments = arguments; + } } } diff --git a/src/main/java/alfio/manager/system/AdminJobExecutor.java b/src/main/java/alfio/manager/system/AdminJobExecutor.java index f4c1364690..250fee3691 100644 --- a/src/main/java/alfio/manager/system/AdminJobExecutor.java +++ b/src/main/java/alfio/manager/system/AdminJobExecutor.java @@ -24,14 +24,25 @@ public interface AdminJobExecutor { enum JobName { - CHECK_OFFLINE_PAYMENTS, - SEND_TICKET_ASSIGNMENT_REMINDER, - SEND_OFFLINE_PAYMENT_REMINDER, - UNKNOWN, - SEND_OFFLINE_PAYMENT_TO_ORGANIZER, - REGENERATE_INVOICES, - ASSIGN_TICKETS_TO_SUBSCRIBERS, - EXECUTE_EXTENSION; + CHECK_OFFLINE_PAYMENTS(false), + SEND_TICKET_ASSIGNMENT_REMINDER(false), + SEND_OFFLINE_PAYMENT_REMINDER(false), + UNKNOWN(false), + SEND_OFFLINE_PAYMENT_TO_ORGANIZER(false), + REGENERATE_INVOICES(false), + ASSIGN_TICKETS_TO_SUBSCRIBERS(false), + EXECUTE_EXTENSION(true), + RETRY_RESERVATION_CONFIRMATION(true); + + private final boolean allowsMultiple; + + JobName(boolean allowsMultiple) { + this.allowsMultiple = allowsMultiple; + } + + public boolean allowsMultipleScheduling() { + return allowsMultiple; + } public static JobName safeValueOf(String value) { return Arrays.stream(values()) diff --git a/src/main/java/alfio/manager/system/AdminJobManager.java b/src/main/java/alfio/manager/system/AdminJobManager.java index 94527157a0..d9595d7d1e 100644 --- a/src/main/java/alfio/manager/system/AdminJobManager.java +++ b/src/main/java/alfio/manager/system/AdminJobManager.java @@ -22,10 +22,10 @@ import alfio.model.system.AdminJobSchedule; import alfio.repository.system.AdminJobQueueRepository; import alfio.util.ClockProvider; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.Transactional; @@ -42,15 +42,17 @@ import static java.util.stream.Collectors.*; @Transactional -@Slf4j public class AdminJobManager { + private static final Logger log = LoggerFactory.getLogger(AdminJobManager.class); + static final int MAX_ATTEMPTS = 17; // will retry for approximately 36h - private static final Set ADMIN_JOBS = EnumSet.complementOf(EnumSet.of(JobName.EXECUTE_EXTENSION)) - .stream() + private static final Set REGULAR = EnumSet.complementOf(EnumSet.of(JobName.EXECUTE_EXTENSION, JobName.RETRY_RESERVATION_CONFIRMATION)); + private static final Set ADMIN_JOBS = REGULAR.stream() .map(Enum::name) .collect(toSet()); private static final Set EXTENSIONS_JOB = Set.of(JobName.EXECUTE_EXTENSION.name()); + private static final Set RESERVATIONS_JOB = Set.of(JobName.RETRY_RESERVATION_CONFIRMATION.name()); private final Map> executorsByJobId; private final AdminJobQueueRepository adminJobQueueRepository; private final TransactionTemplate nestedTransactionTemplate; @@ -74,19 +76,15 @@ public AdminJobManager(List jobExecutors, this.clockProvider = clockProvider; } - @Scheduled(fixedDelay = 1000L) - void processPendingExtensionRetry() { - log.trace("Processing pending extensions retry"); - processPendingExtensionRetry(ZonedDateTime.now(clockProvider.getClock())); - log.trace("done processing pending extensions retry"); - } - // internal method invoked by tests void processPendingExtensionRetry(ZonedDateTime timestamp) { internalProcessPendingSchedules(adminJobQueueRepository.loadPendingSchedules(EXTENSIONS_JOB, timestamp)); } - @Scheduled(fixedDelay = 60 * 1000) + void processPendingReservationsRetry(ZonedDateTime timestamp) { + internalProcessPendingSchedules(adminJobQueueRepository.loadPendingSchedules(RESERVATIONS_JOB, timestamp)); + } + void processPendingRequests() { log.trace("Processing pending requests"); internalProcessPendingSchedules(adminJobQueueRepository.loadPendingSchedules(ADMIN_JOBS, ZonedDateTime.now(clockProvider.getClock()))); @@ -102,12 +100,11 @@ private void internalProcessPendingSchedules(List pendingSched var partitionedResults = scheduleWithResults.getRight().stream().collect(Collectors.partitioningBy(Result::isSuccess)); if(!partitionedResults.get(false).isEmpty()) { partitionedResults.get(false).forEach(r -> log.warn("Processing failed for {}: {}", schedule.getJobName(), r.getErrors())); - if (schedule.getJobName() != JobName.EXECUTE_EXTENSION || schedule.getAttempts() > MAX_ATTEMPTS) { + if (REGULAR.contains(schedule.getJobName()) || schedule.getAttempts() > MAX_ATTEMPTS) { adminJobQueueRepository.updateSchedule(schedule.getId(), AdminJobSchedule.Status.FAILED, ZonedDateTime.now(clockProvider.getClock()), Map.of()); } else { var nextExecution = getNextExecution(schedule.getAttempts()); - var extensionName = schedule.getMetadata().get("extensionName"); - log.debug("scheduling failed extension {} to be executed at {}", extensionName, nextExecution); + logReschedule(nextExecution, schedule.getMetadata(), schedule.getJobName()); adminJobQueueRepository.scheduleRetry(schedule.getId(), nextExecution); } } else { @@ -126,7 +123,6 @@ static ZonedDateTime getNextExecution(int currentAttempt) { .plusSeconds((long) Math.pow(2, currentAttempt + 1D)); } - @Scheduled(cron = "#{environment.acceptsProfiles('dev') ? '0 * * * * *' : '0 0 0 * * *'}") void cleanupExpiredRequests() { log.trace("Cleanup expired requests"); ZonedDateTime now = ZonedDateTime.now(clockProvider.getClock()); @@ -164,7 +160,10 @@ private Pair>> processPendingRequest(Admin public static Function executionScheduler(JobName jobName, Map metadata, ZonedDateTime executionTime) { return adminJobQueueRepository -> { try { - int result = adminJobQueueRepository.schedule(jobName, executionTime, metadata); + int result = adminJobQueueRepository.schedule(jobName, executionTime, metadata, + // by setting a null value, we actually disable the unique constraint for this job name + // and allow multiple rows to be present for the same timestamp + jobName.allowsMultipleScheduling() ? null : "N"); if (result == 0) { log.trace("Possible duplication detected while inserting {}", jobName); } @@ -175,4 +174,15 @@ public static Function executionScheduler(JobN } }; } + + private static void logReschedule(ZonedDateTime nextExecution, Map metadata, JobName jobName) { + String name; + boolean isExtension = jobName == JobName.EXECUTE_EXTENSION; + if (isExtension) { + name = String.valueOf(metadata.get("extensionName")); + } else { + name = String.valueOf(metadata.get("reservationId")); + } + log.debug("scheduling failed {} {} to be executed at {}", isExtension ? "extension" : "reservation", name, nextExecution); + } } diff --git a/src/main/java/alfio/manager/system/AdminJobManagerScheduler.java b/src/main/java/alfio/manager/system/AdminJobManagerScheduler.java new file mode 100644 index 0000000000..0612bc7c5a --- /dev/null +++ b/src/main/java/alfio/manager/system/AdminJobManagerScheduler.java @@ -0,0 +1,68 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.system; + +import alfio.config.Initializer; +import alfio.util.ClockProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.ZonedDateTime; + +@Component +@Profile("!" + Initializer.PROFILE_DISABLE_JOBS) +public class AdminJobManagerScheduler { + + private static final Logger log = LoggerFactory.getLogger(AdminJobManagerScheduler.class); + private final AdminJobManager adminJobManager; + private final ClockProvider clockProvider; + + public AdminJobManagerScheduler(AdminJobManager adminJobManager, + ClockProvider clockProvider) { + this.adminJobManager = adminJobManager; + this.clockProvider = clockProvider; + } + + @Scheduled(fixedDelay = 1000L) + void processPendingExtensionRetry() { + log.trace("Processing pending extensions retry"); + adminJobManager.processPendingExtensionRetry(ZonedDateTime.now(clockProvider.getClock())); + log.trace("done processing pending extensions retry"); + } + + @Scheduled(fixedDelay = 1000L) + void processPendingReservationsRetry() { + log.trace("Processing pending reservations retry"); + adminJobManager.processPendingReservationsRetry(ZonedDateTime.now(clockProvider.getClock())); + log.trace("done processing pending reservations retry"); + } + + @Scheduled(fixedDelay = 60 * 1000) + void processPendingRequests() { + log.trace("Processing pending requests"); + adminJobManager.processPendingRequests(); + log.trace("done processing pending requests"); + } + + @Scheduled(cron = "#{environment.acceptsProfiles('dev') ? '0 * * * * *' : '0 0 0 * * *'}") + void cleanupExpiredRequests() { + adminJobManager.cleanupExpiredRequests(); + } +} diff --git a/src/main/java/alfio/manager/system/BaseMailer.java b/src/main/java/alfio/manager/system/BaseMailer.java new file mode 100644 index 0000000000..a3da8b34a8 --- /dev/null +++ b/src/main/java/alfio/manager/system/BaseMailer.java @@ -0,0 +1,64 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.system; + +import alfio.manager.system.ConfigurationManager.MaybeConfiguration; +import alfio.model.system.ConfigurationKeys; +import alfio.repository.user.OrganizationRepository; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import org.apache.commons.lang3.StringUtils; + +import java.time.Duration; +import java.util.Map; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; + +abstract class BaseMailer implements Mailer { + + static final String MISSING_CONFIG_MESSAGE = "config cannot be null"; + private final OrganizationRepository organizationRepository; + private static final Cache ORG_ADDRESS_CACHE = Caffeine.newBuilder() + .expireAfterWrite(Duration.ofMinutes(1L)) + .build(); + + BaseMailer(OrganizationRepository organizationRepository) { + this.organizationRepository = organizationRepository; + } + + void setReplyToIfPresent(Map conf, + int organizationId, + Consumer replyToSetter) { + var replyToConfig = requireNonNull(requireNonNull(conf, MISSING_CONFIG_MESSAGE).get(ConfigurationKeys.MAIL_REPLY_TO), "MAIL_REPLY_TO is required") + .getValueOrDefault(""); + if (StringUtils.isNotBlank(replyToConfig)) { + replyToSetter.accept(replyToConfig); + } else if(requireNonNull(conf.get(ConfigurationKeys.MAIL_SET_ORG_REPLY_TO), "MAIL_SET_ORG_REPLY_TO is required").getValueAsBooleanOrDefault()) { + var address = ORG_ADDRESS_CACHE.get(organizationId, id -> { + var organization = organizationRepository.getById(organizationId); + if (StringUtils.isNotBlank(organization.getEmail())) { + return organization.getEmail(); + } + return null; + }); + if (StringUtils.isNotBlank(address)) { + replyToSetter.accept(address); + } + } + } +} diff --git a/src/main/java/alfio/manager/system/ConfigurationLevels.java b/src/main/java/alfio/manager/system/ConfigurationLevels.java index e47450d0b5..49c496a4e3 100644 --- a/src/main/java/alfio/manager/system/ConfigurationLevels.java +++ b/src/main/java/alfio/manager/system/ConfigurationLevels.java @@ -17,7 +17,6 @@ package alfio.manager.system; import alfio.model.system.ConfigurationPathLevel; -import lombok.AllArgsConstructor; import java.util.OptionalInt; @@ -39,10 +38,13 @@ public ConfigurationPathLevel getPathLevel() { } } - @AllArgsConstructor static class OrganizationLevel implements ConfigurationLevel { final int organizationId; + OrganizationLevel(int organizationId) { + this.organizationId = organizationId; + } + @Override public ConfigurationPathLevel getPathLevel() { return ORGANIZATION; @@ -54,11 +56,15 @@ public OptionalInt getOrganizationId() { } } - @AllArgsConstructor static class EventLevel implements ConfigurationLevel { final int organizationId; final int eventId; + EventLevel(int organizationId, int eventId) { + this.organizationId = organizationId; + this.eventId = eventId; + } + @Override public ConfigurationPathLevel getPathLevel() { return EVENT; @@ -75,12 +81,18 @@ public OptionalInt getEventId() { } } - @AllArgsConstructor + static class CategoryLevel implements ConfigurationLevel { final int organizationId; final int eventId; final int categoryId; + CategoryLevel(int organizationId, int eventId, int categoryId) { + this.organizationId = organizationId; + this.eventId = eventId; + this.categoryId = categoryId; + } + @Override public ConfigurationPathLevel getPathLevel() { return TICKET_CATEGORY; diff --git a/src/main/java/alfio/manager/system/ConfigurationManager.java b/src/main/java/alfio/manager/system/ConfigurationManager.java index f9574a2384..c0eecbd45f 100644 --- a/src/main/java/alfio/manager/system/ConfigurationManager.java +++ b/src/main/java/alfio/manager/system/ConfigurationManager.java @@ -19,15 +19,13 @@ import alfio.config.Initializer; import alfio.controller.api.v2.model.AlfioInfo; import alfio.controller.api.v2.model.AnalyticsConfiguration; +import alfio.controller.api.v2.model.WalletConfiguration; import alfio.controller.api.v2.user.support.PurchaseContextInfoBuilder; import alfio.manager.system.ConfigurationLevels.CategoryLevel; import alfio.manager.system.ConfigurationLevels.EventLevel; import alfio.manager.system.ConfigurationLevels.OrganizationLevel; import alfio.manager.user.UserManager; -import alfio.model.Configurable; -import alfio.model.EventAndOrganizationId; -import alfio.model.PurchaseContext; -import alfio.model.TicketReservation; +import alfio.model.*; import alfio.model.modification.ConfigurationModification; import alfio.model.system.Configuration; import alfio.model.system.Configuration.*; @@ -40,18 +38,21 @@ import alfio.repository.EventRepository; import alfio.repository.system.ConfigurationRepository; import com.github.benmanes.caffeine.cache.Cache; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.IterableUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpSession; +import java.math.BigInteger; +import java.security.SecureRandom; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; @@ -61,16 +62,16 @@ import static alfio.model.system.ConfigurationKeys.*; import static alfio.model.system.ConfigurationPathLevel.*; -import static java.util.stream.Collectors.toList; @Transactional -@Log4j2 -@RequiredArgsConstructor public class ConfigurationManager { + private static final Logger log = LoggerFactory.getLogger(ConfigurationManager.class); + private static final Map> ORGANIZATION_CONFIGURATION = collectConfigurationKeysByCategory(ORGANIZATION); private static final Map> EVENT_CONFIGURATION = collectConfigurationKeysByCategory(ConfigurationPathLevel.EVENT); private static final Map> CATEGORY_CONFIGURATION = collectConfigurationKeysByCategory(ConfigurationPathLevel.TICKET_CATEGORY); + private static final String DELETE_ERROR = "User is not owner of the organization. Therefore, delete is not allowed."; private final ConfigurationRepository configurationRepository; private final UserManager userManager; @@ -78,34 +79,50 @@ public class ConfigurationManager { private final ExternalConfiguration externalConfiguration; private final Environment environment; private final Cache, Map> oneMinuteCache; + private final SecureRandom secureRandom = new SecureRandom(); + + public ConfigurationManager(ConfigurationRepository configurationRepository, + UserManager userManager, + EventRepository eventRepository, + ExternalConfiguration externalConfiguration, + Environment environment, + Cache, + Map> oneMinuteCache) { + this.configurationRepository = configurationRepository; + this.userManager = userManager; + this.eventRepository = eventRepository; + this.externalConfiguration = externalConfiguration; + this.environment = environment; + this.oneMinuteCache = oneMinuteCache; + } //TODO: refactor, not the most beautiful code, find a better solution... private Optional findByConfigurationPathAndKey(ConfigurationPath path, ConfigurationKeys key) { var keyAsString = key.getValue(); var configList = new ArrayList<>(externalConfiguration.load(keyAsString)); switch (path.pathLevel()) { - case SYSTEM: + case SYSTEM -> { configList.addAll(configurationRepository.findByKeyAtSystemLevel(keyAsString)); return selectPath(configList); - case ORGANIZATION: { + } + case ORGANIZATION -> { OrganizationConfigurationPath o = (OrganizationConfigurationPath) path; configList.addAll(configurationRepository.findByOrganizationAndKey(o.getId(), key.getValue())); return selectPath(configList); } - case EVENT: { + case EVENT -> { EventConfigurationPath o = (EventConfigurationPath) path; configList.addAll(configurationRepository.findByEventAndKey(o.getOrganizationId(), o.getId(), keyAsString)); return selectPath(configList); } - case TICKET_CATEGORY: { + case TICKET_CATEGORY -> { TicketCategoryConfigurationPath o = (TicketCategoryConfigurationPath) path; configList.addAll(configurationRepository.findByTicketCategoryAndKey(o.getOrganizationId(), o.getEventId(), o.getId(), keyAsString)); return selectPath(configList); } - default: - throw new IllegalStateException("Can't reach here"); + default -> throw new IllegalStateException("Can't reach here"); } } @@ -124,19 +141,16 @@ private Optional selectPath(List conf) { public void saveConfig(ConfigurationPathKey pathKey, String value) { ConfigurationPath path = pathKey.getPath(); switch (path.pathLevel()) { - case SYSTEM: - saveSystemConfiguration(pathKey.getKey(), value); - break; - case ORGANIZATION: + case SYSTEM -> saveSystemConfiguration(pathKey.getKey(), value); + case ORGANIZATION -> { OrganizationConfigurationPath orgPath = (OrganizationConfigurationPath) path; saveOrganizationConfiguration(orgPath.getId(), pathKey.getKey().name(), value); - break; - case EVENT: + } + case EVENT -> { EventConfigurationPath eventPath = (EventConfigurationPath) path; saveEventConfiguration(eventPath.getId(), eventPath.getOrganizationId(), pathKey.getKey().name(), value); - break; - default: - throw new IllegalStateException("can't reach here"); + } + default -> throw new IllegalStateException("can't reach here"); } } @@ -223,7 +237,7 @@ public void saveSystemConfiguration(ConfigurationKeys key, String value) { Optional conf = findByConfigurationPathAndKey(Configuration.system(), key); if(key.isBooleanComponentType()) { Optional state = getThreeStateValue(value); - if(conf.isPresent()) { + if(conf.filter(c -> c.getConfigurationPathLevel() != EXTERNAL).isPresent()) { if(state.isPresent()) { configurationRepository.update(key.getValue(), value); } else { @@ -257,7 +271,7 @@ public boolean isBasicConfigurationNeeded() { boolean absent = externalConfiguration.getSingle(key.getValue()) .or(() -> configurationRepository.findOptionalByKey(key.getValue())).isEmpty(); if (absent) { - log.warn("cannot find a value for " + key.getValue()); + log.warn("cannot find a value for {}", key.getValue()); } return absent; }); @@ -279,8 +293,7 @@ public Map> loadOrganizat List toBeRemoved = PaymentProxy.availableProxies() .stream() .filter(pp -> paymentMethodsBlacklist.contains(pp.getKey())) - .flatMap(pp -> pp.getSettingCategories().stream()) - .collect(toList()); + .flatMap(pp -> pp.getSettingCategories().stream()).toList(); if(toBeRemoved.isEmpty()) { return result; @@ -377,7 +390,7 @@ private Map> groupByCateg ConfigurationKeys.SettingCategory key = e.getKey(); Set entries = new TreeSet<>(e.getValue()); if(existing.containsKey(key)) { - List configurations = existing.get(key).stream().filter(Predicate.not(Configuration::isInternal)).collect(Collectors.toList()); + List configurations = existing.get(key).stream().filter(Predicate.not(Configuration::isInternal)).toList(); configurations.forEach(entries::remove); entries.addAll(configurations); } @@ -391,13 +404,11 @@ public Map> loadAllSystem return Collections.emptyMap(); } final List existing = configurationRepository.findSystemConfiguration() - .stream() - .filter(c -> !ConfigurationKeys.fromString(c.getKey()).isInternal()) - .collect(toList()); + .stream() + .filter(c -> !ConfigurationKeys.fromString(c.getKey()).isInternal()).toList(); final List missing = Arrays.stream(ConfigurationKeys.visible()) - .filter(k -> existing.stream().noneMatch(c -> c.getKey().equals(k.getValue()))) - .map(mapEmptyKeys(ConfigurationPathLevel.SYSTEM)) - .collect(toList()); + .filter(k -> existing.stream().noneMatch(c -> c.getKey().equals(k.getValue()))) + .map(mapEmptyKeys(ConfigurationPathLevel.SYSTEM)).toList(); List result = new ArrayList<>(existing); result.addAll(missing); return result.stream().sorted().collect(groupByCategory()); @@ -416,21 +427,21 @@ public void deleteKey(String key) { } public void deleteOrganizationLevelByKey(String key, int organizationId, String username) { - Validate.isTrue(userManager.isOwnerOfOrganization(userManager.findUserByUsername(username), organizationId), "User is not owner of the organization. Therefore, delete is not allowed."); + Validate.isTrue(userManager.isOwnerOfOrganization(userManager.findUserByUsername(username), organizationId), DELETE_ERROR); configurationRepository.deleteOrganizationLevelByKey(key, organizationId); } public void deleteEventLevelByKey(String key, int eventId, String username) { EventAndOrganizationId event = eventRepository.findEventAndOrganizationIdById(eventId); Validate.notNull(event, "Wrong event id"); - Validate.isTrue(userManager.isOwnerOfOrganization(userManager.findUserByUsername(username), event.getOrganizationId()), "User is not owner of the organization. Therefore, delete is not allowed."); + Validate.isTrue(userManager.isOwnerOfOrganization(userManager.findUserByUsername(username), event.getOrganizationId()), DELETE_ERROR); configurationRepository.deleteEventLevelByKey(key, eventId); } public void deleteCategoryLevelByKey(String key, int eventId, int categoryId, String username) { EventAndOrganizationId event = eventRepository.findEventAndOrganizationIdById(eventId); Validate.notNull(event, "Wrong event id"); - Validate.isTrue(userManager.isOwnerOfOrganization(userManager.findUserByUsername(username), event.getOrganizationId()), "User is not owner of the organization. Therefore, delete is not allowed."); + Validate.isTrue(userManager.isOwnerOfOrganization(userManager.findUserByUsername(username), event.getOrganizationId()), DELETE_ERROR); configurationRepository.deleteCategoryLevelByKey(key, eventId, categoryId); } @@ -483,6 +494,13 @@ public boolean isRecaptchaForOfflinePaymentAndFreeEnabled(ConfigurationLevel con } // https://github.com/alfio-event/alf.io/issues/573 + + public boolean canAttachBillingDocumentToConfirmationEmail(Configurable configurable) { + var config = getFor(List.of(ENABLE_ITALY_E_INVOICING, ITALY_E_INVOICING_SEND_PROFORMA), configurable.getConfigurationLevel()); + return !isItalianEInvoicingEnabled(config) + || config.get(ITALY_E_INVOICING_SEND_PROFORMA).getValueAsBooleanOrDefault(); + } + public boolean canGenerateReceiptOrInvoiceToCustomer(Configurable configurable) { return !isItalianEInvoicingEnabled(configurable); } @@ -532,23 +550,21 @@ public MaybeConfiguration getFor(ConfigurationKeys key, ConfigurationLevel confi public Map getFor(Collection keys, ConfigurationLevel configurationLevel) { var keysAsString = keys.stream().map(ConfigurationKeys::getValue).collect(Collectors.toSet()); List found = new ArrayList<>(externalConfiguration.getAll(keysAsString)); - switch(configurationLevel.getPathLevel()) { - case SYSTEM: - found.addAll(configurationRepository.findByKeysAtSystemLevel(keysAsString)); - break; - case ORGANIZATION: - found.addAll(configurationRepository.findByOrganizationAndKeys(((OrganizationLevel)configurationLevel).organizationId, keysAsString)); - break; - case EVENT: + switch (configurationLevel.getPathLevel()) { + case SYSTEM -> found.addAll(configurationRepository.findByKeysAtSystemLevel(keysAsString)); + case ORGANIZATION -> + found.addAll(configurationRepository.findByOrganizationAndKeys(((OrganizationLevel) configurationLevel).organizationId, keysAsString)); + case EVENT -> { var eventLevel = (EventLevel) configurationLevel; found.addAll(configurationRepository.findByEventAndKeys(eventLevel.organizationId, eventLevel.eventId, keysAsString)); - break; - case TICKET_CATEGORY: + } + case TICKET_CATEGORY -> { var categoryLevel = (CategoryLevel) configurationLevel; found.addAll(configurationRepository.findByTicketCategoryAndKeys(categoryLevel.organizationId, categoryLevel.eventId, categoryLevel.categoryId, keysAsString)); - break; - default: - break; + } + default -> { + // ignore EXTERNAL + } } return buildKeyConfigurationMapResult(keys, found); } @@ -579,11 +595,13 @@ public List getBlacklistedMethodsForReservation(PurchaseContext p return categoryIds.stream() .filter(blacklistForCategories::containsKey) .flatMap(id -> Arrays.stream(blacklistForCategories.get(id).split(","))) + .filter(StringUtils::isNotBlank) .map(name -> PaymentProxy.valueOf(name).getPaymentMethod()) - .collect(toList()); - } else if (categoryIds.size() > 0) { + .toList(); + } else if (!categoryIds.isEmpty()) { return configurationRepository.findByKeyAtCategoryLevel(e.getId(), e.getOrganizationId(), IterableUtils.get(categoryIds, 0), PAYMENT_METHODS_BLACKLIST.name()) - .map(v -> Arrays.stream(v.getValue().split(",")).map(name -> PaymentProxy.valueOf(name).getPaymentMethod()).collect(toList())) + .filter(v -> StringUtils.isNotBlank(v.getValue())) + .map(v -> Arrays.stream(v.getValue().split(",")).map(name -> PaymentProxy.valueOf(name).getPaymentMethod()).toList()) .orElse(List.of()); } else { return List.of(); @@ -595,6 +613,17 @@ private static boolean toBeSaved(ConfigurationModification c) { return Optional.ofNullable(c.getId()).orElse(-1) > -1 || !StringUtils.isBlank(c.getValue()); } + public List getCategoriesWithNoTaxes(List categoriesIds) { + if (categoriesIds.isEmpty()) { + return List.of(); + } + return configurationRepository.getCategoriesWithFlag(categoriesIds, APPLY_TAX_TO_CATEGORY.name(), BooleanUtils.FALSE); + } + + public boolean noTaxesFlagDefinedFor(List categories) { + return !getCategoriesWithNoTaxes(categories.stream().map(TicketCategory::getId).toList()).isEmpty(); + } + public static class MaybeConfiguration { @SuppressWarnings("OptionalUsedAsFieldOrParameterType") private final Optional configuration; @@ -689,7 +718,10 @@ public AlfioInfo getInfo(HttpSession session) { ENABLE_EU_VAT_DIRECTIVE, COUNTRY_OF_BUSINESS, ENABLE_REVERSE_CHARGE_IN_PERSON, - ENABLE_REVERSE_CHARGE_ONLINE); + ENABLE_REVERSE_CHARGE_ONLINE, + ANNOUNCEMENT_BANNER_CONTENT, + ENABLE_WALLET, + ENABLE_PASS); var conf = getFor(options, ConfigurationLevel.system()); var analyticsConf = AnalyticsConfiguration.build(conf, session); @@ -700,7 +732,9 @@ public AlfioInfo getInfo(HttpSession session) { analyticsConf, conf.get(GLOBAL_PRIVACY_POLICY).getValueOrNull(), conf.get(GLOBAL_TERMS).getValueOrNull(), - PurchaseContextInfoBuilder.invoicingInfo(this, conf)); + PurchaseContextInfoBuilder.invoicingInfo(this, conf), + StringUtils.trimToNull(conf.get(ANNOUNCEMENT_BANNER_CONTENT).getValueOrNull()), + new WalletConfiguration(conf.get(ENABLE_WALLET).getValueAsBooleanOrDefault(), conf.get(ENABLE_PASS).getValueAsBooleanOrDefault())); } public Map getPublicOpenIdConfiguration() { @@ -717,4 +751,25 @@ public String baseUrl(PurchaseContext purchaseContext) { .orElseGet(() -> ConfigurationLevel.organization(purchaseContext.getOrganizationId())); return StringUtils.removeEnd(getFor(BASE_URL, configurationLevel).getRequiredValue(), "/"); } + + public String retrieveSystemApiKey(boolean rotate) { + Optional existing = configurationRepository.findOptionalByKey(SYSTEM_API_KEY.name()); + String apiKeyValue; + if(existing.isPresent() && rotate) { + apiKeyValue = generateApiKey(); + configurationRepository.update(SYSTEM_API_KEY.name(), apiKeyValue); + } else if(existing.isPresent()) { + apiKeyValue = existing.get().getValue(); + } else { + apiKeyValue = generateApiKey(); + configurationRepository.insert(SYSTEM_API_KEY.name(), apiKeyValue, SYSTEM_API_KEY.getDescription()); + } + return apiKeyValue; + } + + private String generateApiKey() { + var bytes = new byte[48]; + secureRandom.nextBytes(bytes); + return new BigInteger(1, bytes).toString(36); + } } diff --git a/src/main/java/alfio/manager/system/DataMigrator.java b/src/main/java/alfio/manager/system/DataMigrator.java index 55b9d882fd..11f86bfa96 100644 --- a/src/main/java/alfio/manager/system/DataMigrator.java +++ b/src/main/java/alfio/manager/system/DataMigrator.java @@ -27,10 +27,11 @@ import alfio.repository.system.EventMigrationRepository; import alfio.util.ClockProvider; import alfio.util.MonetaryUtil; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.namedparam.EmptySqlParameterSource; @@ -57,9 +58,10 @@ @Component @Transactional(readOnly = true) -@Log4j2 public class DataMigrator { + private static final Logger log = LoggerFactory.getLogger(DataMigrator.class); + private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d\\.)([0-9.]*)(-SNAPSHOT)?"); private static final Map PRICE_UPDATE_BY_KEY = new LinkedHashMap<>(); private final EventMigrationRepository eventMigrationRepository; @@ -288,8 +290,14 @@ private void fillDescriptions(Event event) { * in order to ensure backward compatibility */ private void fixAvailableSeats(Event event) { - int availableSeats = eventRepository.countExistingTickets(event.getId()); - eventRepository.updatePrices(event.getCurrency(), availableSeats, event.isVatIncluded(), event.getVat(), event.getAllowedPaymentProxies().stream().map(PaymentProxy::name).collect(joining(",")), event.getId(), event.getVatStatus(), event.getSrcPriceCts()); + try { + int availableSeats = eventRepository.countExistingTickets(event.getId()); + var paymentProxies = event.getAllowedPaymentProxies().stream().map(PaymentProxy::name).collect(joining(",")); + eventRepository.updatePrices(event.getCurrency(), availableSeats, event.isVatIncluded(), + event.getVat(), paymentProxies, event.getId(), event.getVatStatus(), event.getSrcPriceCts()); + } catch (Exception ex) { + log.trace("got exception while fixing available seats", ex); + } } boolean needsFixing(EventMigration eventMigration) { @@ -439,7 +447,7 @@ public VatStatus getVatStatus() { @Override public Optional getDiscount() { return Optional.ofNullable(ticket.get("discount_amount")) - .map(amount -> new PromoCodeDiscount(0, "", eventId, null, null, null, (int) amount, PromoCodeDiscount.DiscountType.valueOf((String) ticket.get("discount_type")), "", null, null, null, PromoCodeDiscount.CodeType.DISCOUNT, null)); + .map(amount -> new PromoCodeDiscount(0, "", eventId, null, null, null, (int) amount, PromoCodeDiscount.DiscountType.valueOf((String) ticket.get("discount_type")), "", null, null, null, PromoCodeDiscount.CodeType.DISCOUNT, null, currencyCode)); } }); }) diff --git a/src/main/java/alfio/manager/system/DefaultMailer.java b/src/main/java/alfio/manager/system/DefaultMailer.java index 513a705068..89b0a2e41c 100644 --- a/src/main/java/alfio/manager/system/DefaultMailer.java +++ b/src/main/java/alfio/manager/system/DefaultMailer.java @@ -17,6 +17,7 @@ package alfio.manager.system; import alfio.model.Configurable; +import alfio.repository.user.OrganizationRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @@ -35,16 +36,19 @@ public class DefaultMailer implements Mailer { private final Environment environment; @Autowired - public DefaultMailer(ConfigurationManager configurationManager, Environment environment, HttpClient httpClient) { + public DefaultMailer(ConfigurationManager configurationManager, + Environment environment, + HttpClient httpClient, + OrganizationRepository organizationRepository) { this.configurationManager = configurationManager; this.environment = environment; this.mailers = new HashMap<>(); - this.defaultMailer = new SmtpMailer(configurationManager); + this.defaultMailer = new SmtpMailer(configurationManager, organizationRepository); mailers.put("smtp", defaultMailer); - mailers.put("mailgun", new MailgunMailer(httpClient, configurationManager)); - mailers.put("mailjet", new MailjetMailer(httpClient, configurationManager)); - mailers.put("sendgrid", new SendGridMailer(httpClient, configurationManager)); - mailers.put("disabled", new MockMailer(configurationManager, environment)); + mailers.put("mailgun", new MailgunMailer(httpClient, configurationManager, organizationRepository)); + mailers.put("mailjet", new MailjetMailer(httpClient, configurationManager, organizationRepository)); + mailers.put("sendgrid", new SendGridMailer(httpClient, configurationManager, organizationRepository)); + mailers.put("disabled", new MockMailer(configurationManager, environment, organizationRepository)); } @Override diff --git a/src/main/java/alfio/manager/system/ExternalConfiguration.java b/src/main/java/alfio/manager/system/ExternalConfiguration.java index e2f5a055cb..d309bcfd94 100644 --- a/src/main/java/alfio/manager/system/ExternalConfiguration.java +++ b/src/main/java/alfio/manager/system/ExternalConfiguration.java @@ -26,8 +26,6 @@ import alfio.model.system.ConfigurationKeyValuePathLevel; import alfio.model.system.ConfigurationPathLevel; import lombok.Data; -import lombok.Getter; -import lombok.Setter; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.tuple.Pair; @@ -46,14 +44,28 @@ @Component @Profile("!"+ Initializer.PROFILE_INTEGRATION_TEST) @ConfigurationProperties("alfio.override.system") -@Getter -@Setter public class ExternalConfiguration { private static final String EXTERNAL_EXTENSION_PATH = "::EXTERNAL::"; private static final int EXTERNAL_CONFIGURATION_ID = Integer.MIN_VALUE; private Map settings = new HashMap<>(); private List extensions = new ArrayList<>(); + public Map getSettings() { + return settings; + } + + public void setSettings(Map settings) { + this.settings = settings; + } + + public List getExtensions() { + return extensions; + } + + public void setExtensions(List extensions) { + this.extensions = extensions; + } + public List load(String key) { return getSingle(key).map(List::of).orElse(List.of()); } diff --git a/src/main/java/alfio/manager/system/Mailer.java b/src/main/java/alfio/manager/system/Mailer.java index be9c23471b..547ad5a94f 100644 --- a/src/main/java/alfio/manager/system/Mailer.java +++ b/src/main/java/alfio/manager/system/Mailer.java @@ -26,6 +26,8 @@ public interface Mailer { + String SKIP_PASSBOOK = "skipPassbook"; + void send(Configurable configurable, String fromName, String to, List cc, String subject, String text, Optional html, Attachment... attachment); @Data @@ -75,7 +77,7 @@ public String fileName(String fileName) { public String contentType(String contentType) { return "application/vnd.apple.pkpass"; } - }; + }, SUBSCRIPTION_PDF; public List reinterpretAs() { return Collections.emptyList(); diff --git a/src/main/java/alfio/manager/system/MailgunMailer.java b/src/main/java/alfio/manager/system/MailgunMailer.java index 3471f49108..0726efbcf6 100644 --- a/src/main/java/alfio/manager/system/MailgunMailer.java +++ b/src/main/java/alfio/manager/system/MailgunMailer.java @@ -17,12 +17,13 @@ package alfio.manager.system; import alfio.model.Configurable; +import alfio.model.system.ConfigurationKeys; +import alfio.repository.user.OrganizationRepository; import alfio.util.HttpUtils; -import alfio.util.oauth2.AccessTokenResponseDetails; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -35,15 +36,29 @@ import static alfio.model.system.ConfigurationKeys.*; -@Log4j2 -@AllArgsConstructor -class MailgunMailer implements Mailer { +class MailgunMailer extends BaseMailer { + + private static final Logger log = LoggerFactory.getLogger(MailgunMailer.class); private final HttpClient client; private final ConfigurationManager configurationManager; + MailgunMailer(HttpClient client, + ConfigurationManager configurationManager, + OrganizationRepository organizationRepository) { + super(organizationRepository); + this.client = client; + this.configurationManager = configurationManager; + } + - private static Map getEmailData(String from, String to, String replyTo, List cc, String subject, String text, Optional html) { + + private static Map getEmailData(String from, + String to, + List cc, + String subject, + String text, + Optional html) { Map emailData = new HashMap<>(Map.of( "from", from, "to", to, @@ -54,9 +69,6 @@ private static Map getEmailData(String from, String to, String r if(cc != null && !cc.isEmpty()) { emailData.put("cc", StringUtils.join(cc, ',')); } - if(StringUtils.isNoneBlank(replyTo)) { - emailData.put("h:Reply-To", replyTo); - } html.ifPresent(htmlContent -> emailData.put("html", htmlContent)); return emailData; } @@ -65,7 +77,15 @@ private static Map getEmailData(String from, String to, String r public void send(Configurable configurable, String fromName, String to, List cc, String subject, String text, Optional html, Attachment... attachment) { - var conf = configurationManager.getFor(Set.of(MAILGUN_KEY, MAILGUN_DOMAIN, MAILGUN_EU, MAILGUN_FROM, MAIL_REPLY_TO), configurable.getConfigurationLevel()); + var conf = configurationManager.getFor( + Set.of( + MAILGUN_KEY, + MAILGUN_DOMAIN, + MAILGUN_EU, + MAILGUN_FROM, + MAIL_REPLY_TO, + MAIL_SET_ORG_REPLY_TO), + configurable.getConfigurationLevel()); String apiKey = conf.get(MAILGUN_KEY).getRequiredValue(); String domain = conf.get(MAILGUN_DOMAIN).getRequiredValue(); @@ -76,9 +96,10 @@ public void send(Configurable configurable, String fromName, String to, List"; - var replyTo = conf.get(MAIL_REPLY_TO).getValueOrDefault(""); + var emailData = getEmailData(from, to, cc, subject, text, html); - var emailData = getEmailData(from, to, replyTo, cc, subject, text, html); + setReplyToIfPresent(conf, configurable.getOrganizationId(), + replyTo -> emailData.put("h:Reply-To", replyTo)); var requestBuilder = HttpRequest.newBuilder() .uri(URI.create(baseUrl + domain + "/messages")) diff --git a/src/main/java/alfio/manager/system/MailjetMailer.java b/src/main/java/alfio/manager/system/MailjetMailer.java index 3b9199a96a..df5ee24c16 100644 --- a/src/main/java/alfio/manager/system/MailjetMailer.java +++ b/src/main/java/alfio/manager/system/MailjetMailer.java @@ -17,11 +17,12 @@ package alfio.manager.system; import alfio.model.Configurable; +import alfio.repository.user.OrganizationRepository; import alfio.util.HttpUtils; import alfio.util.Json; -import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URI; @@ -29,17 +30,20 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.*; -import java.util.stream.Collectors; import static alfio.model.system.ConfigurationKeys.*; -@Log4j2 -public class MailjetMailer implements Mailer { +class MailjetMailer extends BaseMailer { + + private static final Logger log = LoggerFactory.getLogger(MailjetMailer.class); private final HttpClient client; private final ConfigurationManager configurationManager; - public MailjetMailer(HttpClient httpClient, ConfigurationManager configurationManager) { + MailjetMailer(HttpClient httpClient, + ConfigurationManager configurationManager, + OrganizationRepository organizationRepository) { + super(organizationRepository); this.client = httpClient; this.configurationManager = configurationManager; } @@ -47,7 +51,8 @@ public MailjetMailer(HttpClient httpClient, ConfigurationManager configurationMa @Override public void send(Configurable configurable, String fromName, String to, List cc, String subject, String text, Optional html, Attachment... attachment) { - var conf = configurationManager.getFor(EnumSet.of(MAILJET_APIKEY_PUBLIC, MAILJET_APIKEY_PRIVATE, MAILJET_FROM, MAIL_REPLY_TO), configurable.getConfigurationLevel()); + var conf = configurationManager.getFor( + EnumSet.of(MAILJET_APIKEY_PUBLIC, MAILJET_APIKEY_PRIVATE, MAILJET_FROM, MAIL_REPLY_TO, MAIL_SET_ORG_REPLY_TO), configurable.getConfigurationLevel()); String apiKeyPublic = conf.get(MAILJET_APIKEY_PUBLIC).getRequiredValue(); @@ -60,7 +65,7 @@ public void send(Configurable configurable, String fromName, String to, List> recipients = new ArrayList<>(); recipients.add(Collections.singletonMap("Email", to)); if(cc != null && !cc.isEmpty()) { - recipients.addAll(cc.stream().map(email -> Collections.singletonMap("Email", email)).collect(Collectors.toList())); + recipients.addAll(cc.stream().map(email -> Collections.singletonMap("Email", email)).toList()); } mailPayload.put("FromEmail", fromEmail); @@ -70,13 +75,11 @@ public void send(Configurable configurable, String fromName, String to, List mailPayload.put("Html-part", h)); mailPayload.put("Recipients", recipients); - String replyTo = conf.get(MAIL_REPLY_TO).getValueOrDefault(""); - if(StringUtils.isNotBlank(replyTo)) { - mailPayload.put("Headers", Collections.singletonMap("Reply-To", replyTo)); - } + setReplyToIfPresent(conf, configurable.getOrganizationId(), + address -> mailPayload.put("Headers", Collections.singletonMap("Reply-To", address))); if(attachment != null && attachment.length > 0) { - mailPayload.put("Attachments", Arrays.stream(attachment).map(MailjetMailer::fromAttachment).collect(Collectors.toList())); + mailPayload.put("Attachments", Arrays.stream(attachment).map(MailjetMailer::fromAttachment).toList()); } HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.mailjet.com/v3/send")) @@ -88,7 +91,7 @@ public void send(Configurable configurable, String fromName, String to, List response = client.send(request, HttpResponse.BodyHandlers.discarding()); if(!HttpUtils.callSuccessful(response)) { - log.warn("sending email was not successful:" + response); + log.warn("sending email was not successful: {}", response); throw new IllegalStateException("Attempt to send a message failed. Result is: "+response.statusCode()); } } catch (IOException e) { diff --git a/src/main/java/alfio/manager/system/MockMailer.java b/src/main/java/alfio/manager/system/MockMailer.java index 0c1d141a31..161e21dacf 100644 --- a/src/main/java/alfio/manager/system/MockMailer.java +++ b/src/main/java/alfio/manager/system/MockMailer.java @@ -17,25 +17,33 @@ package alfio.manager.system; import alfio.model.Configurable; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import alfio.repository.user.OrganizationRepository; import org.springframework.core.env.Environment; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import static alfio.model.system.ConfigurationKeys.MAIL_REPLY_TO; +import static alfio.model.system.ConfigurationKeys.MAIL_SET_ORG_REPLY_TO; -@Log4j2 -@AllArgsConstructor -public class MockMailer implements Mailer { +class MockMailer extends BaseMailer { + + private static final Logger log = LoggerFactory.getLogger(MockMailer.class); private final ConfigurationManager configurationManager; private final Environment environment; + MockMailer(ConfigurationManager configurationManager, + Environment environment, + OrganizationRepository organizationRepository) { + super(organizationRepository); + this.configurationManager = configurationManager; + this.environment = environment; + } + @Override public void send(Configurable configurable, String fromName, String to, List cc, String subject, String text, Optional html, Attachment... attachments) { @@ -47,9 +55,13 @@ public void send(Configurable configurable, String fromName, String to, List "{filename:" +a.getFilename() + ", contentType: " + a.getContentType() + "}") .collect(Collectors.joining(", ")); + var conf = configurationManager.getFor(EnumSet.of(MAIL_REPLY_TO, MAIL_SET_ORG_REPLY_TO), configurable.getConfigurationLevel()); + var replyTo = new AtomicReference(null); + setReplyToIfPresent(conf, configurable.getOrganizationId(), replyTo::set); + log.info("Email: from: {}, replyTo: {}, to: {}, cc: {}, subject: {}, text: {}, html: {}, attachments: {}", fromName, - configurationManager.getFor(MAIL_REPLY_TO, configurable.getConfigurationLevel()).getValueOrDefault(""), + replyTo.get(), to, cc, subject, text, html.orElse("no html"), printedAttachments); } diff --git a/src/main/java/alfio/manager/system/ReservationPriceCalculator.java b/src/main/java/alfio/manager/system/ReservationPriceCalculator.java index f28b81d4e7..b2dafa26ef 100644 --- a/src/main/java/alfio/manager/system/ReservationPriceCalculator.java +++ b/src/main/java/alfio/manager/system/ReservationPriceCalculator.java @@ -22,7 +22,6 @@ import alfio.model.decorator.TicketPriceContainer; import alfio.model.subscription.Subscription; import alfio.util.MonetaryUtil; -import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.tuple.Pair; import java.math.BigDecimal; @@ -33,7 +32,7 @@ import static org.apache.commons.lang3.ObjectUtils.firstNonNull; -@RequiredArgsConstructor + public class ReservationPriceCalculator implements PriceContainer { final TicketReservation reservation; final PromoCodeDiscount discount; @@ -44,6 +43,24 @@ public class ReservationPriceCalculator implements PriceContainer { private final List subscriptions; private final Optional appliedSubscription; + public ReservationPriceCalculator(TicketReservation reservation, + PromoCodeDiscount discount, + List tickets, + List additionalServiceItems, + List additionalServices, + PurchaseContext purchaseContext, + List subscriptions, + Optional appliedSubscription) { + this.reservation = reservation; + this.discount = discount; + this.tickets = tickets; + this.additionalServiceItems = additionalServiceItems; + this.additionalServices = additionalServices; + this.purchaseContext = purchaseContext; + this.subscriptions = subscriptions; + this.appliedSubscription = appliedSubscription; + } + @Override public int getSrcPriceCts() { return tickets.stream().mapToInt(this::getTicketSrcPriceCts).sum() + @@ -62,7 +79,10 @@ public BigDecimal getAppliedDiscount() { if (discount.getDiscountType() == PromoCodeDiscount.DiscountType.FIXED_AMOUNT_RESERVATION) { return MonetaryUtil.centsToUnit(discount.getDiscountAmount() + subscriptionDiscount, reservation.getCurrencyCode()); } - return MonetaryUtil.centsToUnit(tickets.stream().mapToInt(Ticket::getDiscountCts).sum() + + int ticketDiscount = tickets.stream() + .mapToInt(t -> MonetaryUtil.unitToCents(TicketPriceContainer.from(t, reservation.getVatStatus(), reservation.getVatPercentageOrZero(), purchaseContext.getVatStatus(), discount).getAppliedDiscount(), reservation.getCurrencyCode())) + .sum(); + return MonetaryUtil.centsToUnit(ticketDiscount + additionalServiceItems.stream().mapToInt(AdditionalServiceItem::getDiscountCts).sum() + subscriptions.stream().mapToInt(Subscription::getDiscountCts).sum() + subscriptionDiscount, reservation.getCurrencyCode()); } @@ -115,7 +135,7 @@ public static ReservationPriceCalculator from(TicketReservation reservation, Pro } private int getTicketSrcPriceCts(Ticket t) { - if(t.getVatStatus() == VatStatus.INCLUDED_EXEMPT || t.getVatStatus() == VatStatus.NOT_INCLUDED_EXEMPT) { + if(VatStatus.isVatExempt(t.getVatStatus())) { return t.getSrcPriceCts() - Math.abs(t.getVatCts()); // VAT can be negative in some cases } return t.getSrcPriceCts(); diff --git a/src/main/java/alfio/manager/system/SendGridMailer.java b/src/main/java/alfio/manager/system/SendGridMailer.java index dac0a82e82..da2cb54796 100644 --- a/src/main/java/alfio/manager/system/SendGridMailer.java +++ b/src/main/java/alfio/manager/system/SendGridMailer.java @@ -18,12 +18,13 @@ import alfio.model.Configurable; import alfio.model.system.ConfigurationKeys; +import alfio.repository.user.OrganizationRepository; import alfio.util.HttpUtils; import alfio.util.Json; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import java.io.IOException; @@ -32,21 +33,30 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.*; -import java.util.stream.Collectors; import java.util.stream.Stream; -@Log4j2 -@AllArgsConstructor -public class SendGridMailer implements Mailer { +class SendGridMailer extends BaseMailer { + + private static final Logger log = LoggerFactory.getLogger(SendGridMailer.class); private static final String EMAIL = "email"; - private final HttpClient client; + private final HttpClient client; private final ConfigurationManager configurationManager; + SendGridMailer(HttpClient client, + ConfigurationManager configurationManager, + OrganizationRepository organizationRepository) { + super(organizationRepository); + this.client = client; + this.configurationManager = configurationManager; + } + @Override public void send(Configurable configurable, final String fromName, final String to, final List cc, final String subject, final String text, final Optional html, final Attachment... attachment) { - final var config = configurationManager.getFor(Set.of(ConfigurationKeys.SENDGRID_API_KEY, ConfigurationKeys.SENDGRID_FROM, ConfigurationKeys.MAIL_REPLY_TO), configurable.getConfigurationLevel()); + final var config = configurationManager.getFor(EnumSet.of( + ConfigurationKeys.SENDGRID_API_KEY, ConfigurationKeys.SENDGRID_FROM, ConfigurationKeys.MAIL_REPLY_TO, ConfigurationKeys.MAIL_SET_ORG_REPLY_TO), + configurable.getConfigurationLevel()); final var from = config.get(ConfigurationKeys.SENDGRID_FROM).getRequiredValue(); final var personalizations = createPersonalizations(to, cc, subject); final var contents = createContents(text, html); @@ -57,6 +67,8 @@ public void send(Configurable configurable, final String fromName, final String payload.put("from", Map.of(EMAIL, from, "name", fromName)); payload.put("personalizations", personalizations); payload.put("content", contents); + setReplyToIfPresent(config, configurable.getOrganizationId(), + replyTo -> payload.put("reply_to", Map.of(EMAIL, replyTo))); //prepare request final var body = Json.GSON.toJson(payload); final var request = HttpRequest.newBuilder(URI.create("https://api.sendgrid.com/v3/mail/send")) @@ -81,7 +93,7 @@ private List> createPersonalizations(final String to, final final var recipients = new ArrayList<>(); recipients.add(Map.of(EMAIL, to)); if (CollectionUtils.isNotEmpty(cc)) { - recipients.addAll(cc.stream().map(email -> Map.of(EMAIL, email)).collect(Collectors.toList())); + recipients.addAll(cc.stream().map(email -> Map.of(EMAIL, email)).toList()); } return List.of(Map.of("to", recipients, "subject", subject)); } @@ -95,7 +107,7 @@ private List> createContents(final String text, final Option private void addAttachments(final Map payload, final Attachment[] attachment) { final var attachments = Stream.of(attachment) - .map(attach -> Map.of("filename", attach.getFilename(), "content", attach.getSource(), "content_id", attach.getIdentifier().name(), "type", attach.getContentType())).collect(Collectors.toList()); + .map(attach -> Map.of("filename", attach.getFilename(), "content", attach.getSource(), "content_id", attach.getIdentifier().name(), "type", attach.getContentType())).toList(); payload.put("attachments", attachments); } } diff --git a/src/main/java/alfio/manager/system/SmtpMailer.java b/src/main/java/alfio/manager/system/SmtpMailer.java index 32c72248db..9de7ae83cd 100644 --- a/src/main/java/alfio/manager/system/SmtpMailer.java +++ b/src/main/java/alfio/manager/system/SmtpMailer.java @@ -18,10 +18,11 @@ import alfio.model.Configurable; import alfio.model.system.ConfigurationKeys; -import lombok.AllArgsConstructor; -import lombok.extern.log4j.Log4j2; +import alfio.repository.user.OrganizationRepository; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.PropertiesLoaderUtils; @@ -37,35 +38,43 @@ import javax.mail.internet.MimeMessage; import java.io.IOException; import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.*; import static alfio.model.system.ConfigurationKeys.*; +import static java.nio.charset.StandardCharsets.UTF_8; -@Log4j2 -@AllArgsConstructor -class SmtpMailer implements Mailer { - +class SmtpMailer extends BaseMailer { + + private static final Logger log = LoggerFactory.getLogger(SmtpMailer.class); private final ConfigurationManager configurationManager; + SmtpMailer(ConfigurationManager configurationManager, + OrganizationRepository organizationRepository) { + super(organizationRepository); + this.configurationManager = configurationManager; + } + @Override public void send(Configurable configurable, String fromName, String to, List cc, String subject, String text, Optional html, Attachment... attachments) { var conf = configurationManager.getFor(Set.of(SMTP_FROM_EMAIL, MAIL_REPLY_TO, - SMTP_HOST, SMTP_PORT, SMTP_PROTOCOL, + MAIL_SET_ORG_REPLY_TO, SMTP_HOST, SMTP_PORT, SMTP_PROTOCOL, SMTP_USERNAME, SMTP_PASSWORD, SMTP_PROPERTIES), configurable.getConfigurationLevel()); MimeMessagePreparator preparator = mimeMessage -> { - MimeMessageHelper message = html.isPresent() || !ArrayUtils.isEmpty(attachments) ? new MimeMessageHelper(mimeMessage, true, "UTF-8") - : new MimeMessageHelper(mimeMessage, "UTF-8"); + MimeMessageHelper message = html.isPresent() || !ArrayUtils.isEmpty(attachments) ? new MimeMessageHelper(mimeMessage, true, UTF_8.name()) + : new MimeMessageHelper(mimeMessage, UTF_8.name()); message.setSubject(subject); message.setFrom(conf.get(SMTP_FROM_EMAIL).getRequiredValue(), fromName); - String replyTo = conf.get(MAIL_REPLY_TO).getValueOrDefault(""); - if(StringUtils.isNotBlank(replyTo)) { - message.setReplyTo(replyTo); - } + setReplyToIfPresent(conf, configurable.getOrganizationId(), replyTo -> { + try { + message.setReplyTo(replyTo); + } catch (MessagingException e) { + throw new RuntimeException(e); + } + }); message.setTo(to); if(cc != null && !cc.isEmpty()){ message.setCc(cc.toArray(new String[0])); @@ -90,7 +99,7 @@ public void send(Configurable configurable, String fromName, String to, List conf) { JavaMailSenderImpl r = new CustomJavaMailSenderImpl(); - r.setDefaultEncoding("UTF-8"); + r.setDefaultEncoding(UTF_8.name()); r.setHost(conf.get(SMTP_HOST).getRequiredValue()); r.setPort(Integer.parseInt(conf.get(SMTP_PORT).getRequiredValue())); @@ -103,7 +112,7 @@ private static JavaMailSender toMailSender(Map u.getType() == User.Type.PUBLIC) diff --git a/src/main/java/alfio/manager/user/UserManager.java b/src/main/java/alfio/manager/user/UserManager.java index 429b8fb345..3b97e6d3e4 100644 --- a/src/main/java/alfio/manager/user/UserManager.java +++ b/src/main/java/alfio/manager/user/UserManager.java @@ -16,7 +16,7 @@ */ package alfio.manager.user; -import alfio.model.TicketReservationAdditionalInfo; +import alfio.config.authentication.support.APITokenAuthentication; import alfio.model.modification.OrganizationModification; import alfio.model.result.ValidationResult; import alfio.model.user.*; @@ -29,12 +29,13 @@ import alfio.util.PasswordGenerator; import alfio.util.RequestUtils; import ch.digitalfondue.npjt.AffectedRowCountAndKey; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -47,16 +48,16 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static alfio.config.authentication.support.AuthenticationConstants.SYSTEM_API_CLIENT; import static java.util.Objects.requireNonNull; -import static java.util.Objects.requireNonNullElse; import static java.util.stream.Collectors.toList; @Component @Transactional -@RequiredArgsConstructor -@Log4j2 public class UserManager { + private static final Logger log = LoggerFactory.getLogger(UserManager.class); + public static final String ADMIN_USERNAME = "admin"; private static final Pattern SLUG_VALIDATOR = Pattern.compile("^[A-Za-z-_0-9]+$"); private final AuthorityRepository authorityRepository; @@ -66,10 +67,29 @@ public class UserManager { private final PasswordEncoder passwordEncoder; private final InvoiceSequencesRepository invoiceSequencesRepository; + private final FindByIndexNameSessionRepository sessionsByPrincipalFinder; + + public UserManager(AuthorityRepository authorityRepository, + OrganizationRepository organizationRepository, + UserOrganizationRepository userOrganizationRepository, + UserRepository userRepository, + PasswordEncoder passwordEncoder, + InvoiceSequencesRepository invoiceSequencesRepository, + FindByIndexNameSessionRepository sessionsByPrincipalFinder) { + this.authorityRepository = authorityRepository; + this.organizationRepository = organizationRepository; + this.userOrganizationRepository = userOrganizationRepository; + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.invoiceSequencesRepository = invoiceSequencesRepository; + this.sessionsByPrincipalFinder = sessionsByPrincipalFinder; + } + private List getUserAuthorities(User user) { return authorityRepository.findGrantedAuthorities(user.getUsername()); } + @Transactional(readOnly = true) public List findAllUsers(String username) { List organizations = findUserOrganizations(username); Predicate> isNotEmpty = ks -> !ks.isEmpty(); @@ -78,49 +98,61 @@ public List findAllUsers(String username) { .flatMap(org -> { Map> usersAndOrganizations = userOrganizationRepository.findByOrganizationIdsOrderByUserId(organizations.stream().map(Organization::getId).collect(toList())) .stream() - .collect(Collectors.groupingBy(UserOrganization::getUserId)); + .collect(Collectors.groupingBy(UserOrganization::userId)); return Optional.of(usersAndOrganizations.keySet()) .filter(isNotEmpty) .map(ks -> userRepository.findByIds(ks) .stream() .map(u -> { List userOrganizations = usersAndOrganizations.get(u.getId()); - List filteredOrganizations = organizations.stream().filter(o -> userOrganizations.stream().anyMatch(uo -> uo.getOrganizationId() == o.getId())).collect(toList()); + List filteredOrganizations = organizations.stream().filter(o -> userOrganizations.stream().anyMatch(uo -> uo.organizationId() == o.getId())).collect(toList()); List roles = authorityRepository.findRoles(u.getUsername()).stream().map(Role::fromRoleName).collect(toList()); return new UserWithOrganizations(u, filteredOrganizations, roles); }).collect(toList())); }).orElseGet(Collections::emptyList); } + @Transactional(readOnly = true) public List findAllEnabledUsers(String username) { return findUserOrganizations(username) .stream() .flatMap(o -> userOrganizationRepository.findByOrganizationId(o.getId()).stream()) - .map(uo -> userRepository.findById(uo.getUserId())) + .map(uo -> userRepository.findById(uo.userId())) .filter(User::isEnabled) .collect(toList()); } + @Transactional(readOnly = true) public List findAllApiKeysFor(int organizationId) { return userRepository.findAllApiKeysForOrganization(organizationId); } + @Transactional(readOnly = true) public User findUserByUsername(String username) { return userRepository.findEnabledByUsername(username).orElseThrow(IllegalArgumentException::new); } + @Transactional(readOnly = true) public Optional findOptionalEnabledUserByUsername(String username) { return userRepository.findEnabledByUsername(username); } + @Transactional(readOnly = true) public boolean usernameExists(String username) { return userRepository.findIdByUserName(username).isPresent(); } - public User findUser(int id) { + @Transactional(readOnly = true) + public User findUser(int id, Principal principal) { + checkAccessToUserId(principal, id); + return internalFindUser(id); + } + + private User internalFindUser(int id) { return userRepository.findById(id); } + @Transactional(readOnly = true) public Collection getAvailableRoles(String username) { User user = findUserByUsername(username); return isAdmin(user) || isOwner(user) ? EnumSet.of(Role.OWNER, Role.OPERATOR, Role.SUPERVISOR, Role.SPONSOR, Role.API_CONSUMER) : Collections.emptySet(); @@ -131,34 +163,45 @@ public Collection getAvailableRoles(String username) { * @param user * @return user role */ + @Transactional(readOnly = true) public Role getUserRole(User user) { return getUserAuthorities(user).stream().map(Authority::getRole).sorted().findFirst().orElse(Role.OPERATOR); } + @Transactional(readOnly = true) public List findUserOrganizations(String username) { return organizationRepository.findAllForUser(username); } + @Transactional(readOnly = true) public Organization findOrganizationById(int id, String username) { + return findOptionalOrganizationById(id, username).orElseThrow(IllegalArgumentException::new); + } + + @Transactional(readOnly = true) + public Optional findOptionalOrganizationById(int id, String username) { return findUserOrganizations(username) - .stream() - .filter(o -> o.getId() == id) - .findFirst() - .orElseThrow(IllegalArgumentException::new); + .stream() + .filter(o -> o.getId() == id) + .findFirst(); } + @Transactional(readOnly = true) public boolean isAdmin(User user) { return checkRole(user, Collections.singleton(Role.ADMIN)); } + @Transactional(readOnly = true) public boolean isOwner(User user) { return checkRole(user, EnumSet.of(Role.ADMIN, Role.OWNER, Role.API_CONSUMER)); } + @Transactional(readOnly = true) public boolean isOwnerOfOrganization(User user, int organizationId) { - return isAdmin(user) || (isOwner(user) && userOrganizationRepository.findByUserId(user.getId()).stream().anyMatch(uo -> uo.getOrganizationId() == organizationId)); + return isAdmin(user) || (isOwner(user) && userOrganizationRepository.findByUserId(user.getId()).stream().anyMatch(uo -> uo.organizationId() == organizationId)); } + @Transactional(readOnly = true) public boolean isOwnerOfOrganization(String username, int organizationId) { return userRepository.findByUsername(username) .filter(user -> isOwnerOfOrganization(user, organizationId)) @@ -170,7 +213,10 @@ private boolean checkRole(User user, Set expectedRoles) { return authorityRepository.checkRole(user.getUsername(), roleNames); } - public int createOrganization(OrganizationModification om) { + public int createOrganization(OrganizationModification om, Principal principal) { + // + checkIsAdmin(principal); + // var affectedRowNumAndKey = organizationRepository.create(om.getName(), om.getDescription(), om.getEmail(), om.getExternalId(), om.getSlug()); int orgId = affectedRowNumAndKey.getKey(); Validate.isTrue(invoiceSequencesRepository.initFor(orgId) == 2); @@ -178,8 +224,12 @@ public int createOrganization(OrganizationModification om) { } public void updateOrganization(OrganizationModification om, Principal principal) { - boolean isAdmin = RequestUtils.isAdmin(principal); - var currentOrg = organizationRepository.getById(requireNonNull(om.getId())); + // + int orgId = requireNonNull(om.getId()); + checkAccessToOrganizationId(principal, orgId); + // + boolean isAdmin = RequestUtils.isAdmin(principal) || RequestUtils.isSystemApiKey(principal); + var currentOrg = organizationRepository.getById(orgId); organizationRepository.update(om.getId(), om.getName(), om.getDescription(), @@ -188,6 +238,7 @@ public void updateOrganization(OrganizationModification om, Principal principal) isAdmin ? om.getSlug() : currentOrg.getSlug()); } + @Transactional(readOnly = true) public ValidationResult validateOrganizationSlug(OrganizationModification om, Principal principal) { if(!RequestUtils.isAdmin(principal)) { return ValidationResult.failed(new ValidationResult.ErrorDescriptor("slug", "Cannot update Organizer URL.")); @@ -202,6 +253,7 @@ public ValidationResult validateOrganizationSlug(OrganizationModification om, Pr return ValidationResult.success(); } + @Transactional(readOnly = true) public ValidationResult validateOrganization(OrganizationModification om, Principal principal) { if(om.getId() == null && organizationRepository.findByName(om.getName()).isPresent()) { return ValidationResult.failed(new ValidationResult.ErrorDescriptor("name", "There is already another organization with the same name.")); @@ -218,7 +270,11 @@ public ValidationResult validateOrganization(OrganizationModification om, Princi return ValidationResult.success(); } - public void editUser(int id, int organizationId, String username, String firstName, String lastName, String emailAddress, String description, Role role, String currentUsername) { + public void editUser(int id, int organizationId, String username, String firstName, String lastName, String emailAddress, String description, Role role, Principal principal) { + // + checkAccessToUserIdAndNewOrganization(principal, id, organizationId); + // + String currentUsername = principal.getName(); boolean admin = ADMIN_USERNAME.equals(username) && Role.ADMIN == role; if(!admin) { int userOrganizationResult = userOrganizationRepository.updateUserOrganization(id, organizationId); @@ -233,16 +289,17 @@ public void editUser(int id, int organizationId, String username, String firstNa } } - public void updateUserContactInfo(int id, String firstName, String lastName, String emailAddress) { + public void updateCurrentUserContactInfo(String firstName, String lastName, String emailAddress, Principal principal) { + var id = userRepository.findIdByUserName(principal.getName()).orElseThrow(); userRepository.updateContactInfo(id, firstName, lastName, emailAddress); } - public UserWithPassword insertUser(int organizationId, String username, String firstName, String lastName, String emailAddress, Role role, User.Type userType) { - return insertUser(organizationId, username, firstName, lastName, emailAddress, role, userType, null, null); + public UserWithPassword insertUser(int organizationId, String username, String firstName, String lastName, String emailAddress, Role role, User.Type userType, Principal principal) { + return insertUser(organizationId, username, firstName, lastName, emailAddress, role, userType, null, null, principal); } - public UserWithPassword insertUser(int organizationId, String username, String firstName, String lastName, String emailAddress, Role role, User.Type userType, ZonedDateTime validTo, String description) { + public UserWithPassword insertUser(int organizationId, String username, String firstName, String lastName, String emailAddress, Role role, User.Type userType, ZonedDateTime validTo, String description, Principal principal) { if (userType == User.Type.API_KEY) { username = UUID.randomUUID().toString(); firstName = "apikey"; @@ -251,17 +308,20 @@ public UserWithPassword insertUser(int organizationId, String username, String f } String userPassword = PasswordGenerator.generateRandomPassword(); - return insertUser(organizationId, username, firstName, lastName, emailAddress, role, userType, userPassword, validTo, description); + return insertUser(organizationId, username, firstName, lastName, emailAddress, role, userType, userPassword, validTo, description, principal); } - public void bulkInsertApiKeys(int organizationId, Role role, List descriptions) { + public void bulkInsertApiKeys(int organizationId, Role role, List descriptions, Principal principal) { for (String description : descriptions) { - insertUser(organizationId, null, null, null, null, role, User.Type.API_KEY, null, description); + insertUser(organizationId, null, null, null, null, role, User.Type.API_KEY, null, description, principal); } } - public UserWithPassword insertUser(int organizationId, String username, String firstName, String lastName, String emailAddress, Role role, User.Type userType, String userPassword, ZonedDateTime validTo, String description) { + public UserWithPassword insertUser(int organizationId, String username, String firstName, String lastName, String emailAddress, Role role, User.Type userType, String userPassword, ZonedDateTime validTo, String description, Principal principal) { + // + checkAccessToOrganizationId(principal, organizationId); + // Organization organization = organizationRepository.getById(organizationId); AffectedRowCountAndKey result = userRepository.create(username, passwordEncoder.encode(userPassword), firstName, lastName, emailAddress, true, userType, validTo, description); userOrganizationRepository.create(result.getKey(), organization.getId()); @@ -270,34 +330,62 @@ public UserWithPassword insertUser(int organizationId, String username, String f } - public UserWithPassword resetPassword(int userId) { - User user = findUser(userId); + public UserWithPassword resetPassword(int userId, Principal principal) { + // + checkAccessToUserId(principal, userId); + // + User user = internalFindUser(userId); String password = PasswordGenerator.generateRandomPassword(); Validate.isTrue(userRepository.resetPassword(userId, passwordEncoder.encode(password)) == 1, "error during password reset"); + + if (!Objects.requireNonNull(principal).getName().equals(user.getUsername())) { + invalidateSessionsForUser(user.getUsername()); + } + return new UserWithPassword(user, password, UUID.randomUUID().toString()); } - public void updatePassword(String username, String newPassword) { + public void updateCurrentUserPassword(String newPassword, Principal principal) { + var username = principal.getName(); User user = userRepository.findByUsername(username).orElseThrow(IllegalStateException::new); Validate.isTrue(PasswordGenerator.isValid(newPassword), "invalid password"); Validate.isTrue(userRepository.resetPassword(user.getId(), passwordEncoder.encode(newPassword)) == 1, "error during password update"); } - public void deleteUser(int userId, String currentUsername) { + public void deleteUser(int userId, Principal principal) { + // + checkAccessToUserId(principal, userId); + // + var currentUsername = principal.getName(); User currentUser = userRepository.findEnabledByUsername(currentUsername).orElseThrow(IllegalArgumentException::new); Assert.isTrue(userId != currentUser.getId(), "sorry but you cannot delete your own account."); + var userToDelete = userRepository.findById(userId); userRepository.deleteUserAndReferences(userId); + invalidateSessionsForUser(userToDelete.getUsername()); + } + + private void invalidateSessionsForUser(String username) { + var sessionsToInvalidate = sessionsByPrincipalFinder.findByPrincipalName(username).keySet(); + sessionsToInvalidate.forEach(sessionsByPrincipalFinder::deleteById); } - public void enable(int userId, String currentUsername, boolean status) { + public void enable(int userId, boolean status, Principal principal) { + // + checkAccessToUserId(principal, userId); + // + var currentUsername = principal.getName(); User currentUser = userRepository.findEnabledByUsername(currentUsername).orElseThrow(IllegalArgumentException::new); Assert.isTrue(userId != currentUser.getId(), "sorry but you cannot commit suicide"); - userRepository.toggleEnabled(userId, status); + if (!status) { // disable user + var userToDisable = userRepository.findById(userId); + invalidateSessionsForUser(userToDisable.getUsername()); + } } + @Transactional(readOnly = true) public ValidationResult validateUser(Integer id, String username, String firstName, String lastName, String emailAddress) { Optional existing = Optional.ofNullable(id).flatMap(userRepository::findOptionalById); @@ -311,6 +399,7 @@ public ValidationResult validateUser(Integer id, String username, String firstNa .collect(toList())); } + @Transactional(readOnly = true) public ValidationResult validateNewPassword(String username, String oldPassword, String newPassword, String newPasswordConfirm) { return userRepository.findByUsername(username) .map(u -> { @@ -345,4 +434,66 @@ public Integer createPublicUserIfNotExists(String username, String email, String return userRepository.findIdByUserName(username).orElse(null); } + + private void checkIsAdmin(Principal principal) { + if (principal == null) { + return; + } + if (isSystemApiUser(principal)) { + log.trace("Allowing call for System API Key"); + return; + } + if (isAdmin(findUserByUsername(principal.getName()))) { + return; + } + log.warn("User {} is not an admin", principal.getName()); + throw new IllegalArgumentException("User " + principal.getName() + " is not an admin"); + } + + private void checkAccessToUserId(Principal principal, int userId) { + if (principal == null) { + return; + } + var currentUser = findUserByUsername(principal.getName()); + if (isAdmin(currentUser)) { + return; + } + var targetUser = internalFindUser(userId); + var targetUserOrgs = findUserOrganizations(targetUser.getUsername()); + Assert.state(!targetUser.getUsername().equals(ADMIN_USERNAME) && !isAdmin(targetUser), "Targeted user cannot be admin"); + Assert.isTrue(targetUserOrgs.size() == 1, "Targeted user can only be in one organization"); + for (var org : targetUserOrgs) { + if (isOwnerOfOrganization(currentUser, org.getId())) { + return; + } + } + log.warn("User {} does not have access to userId {}", principal.getName(), userId); + throw new IllegalStateException("User " + principal.getName() + " does not have access to userId " + userId); + } + + private void checkAccessToUserIdAndNewOrganization(Principal principal, int userId, int newOrganization) { + checkAccessToUserId(principal, userId); + checkAccessToOrganizationId(principal, newOrganization); + } + + private void checkAccessToOrganizationId(Principal principal, int organizationId) { + if (principal == null) { + return; + } + if (isSystemApiUser(principal)) { + log.trace("Allowing access to Organization " + organizationId + " to System API Key"); + return; + } + if (isOwnerOfOrganization(principal.getName(), organizationId)) { + return; + } + log.warn("User {} don't have access to organizationId {}", principal.getName(), organizationId); + throw new IllegalArgumentException("User " + principal.getName() + " don't have access to organizationId " + organizationId); + } + + private boolean isSystemApiUser(Principal principal) { + return principal instanceof APITokenAuthentication + && ((APITokenAuthentication)principal).getAuthorities().stream() + .allMatch(authority -> authority.getAuthority().equals("ROLE_" + SYSTEM_API_CLIENT)); + } } diff --git a/src/main/java/alfio/manager/wallet/EventTicketClass.java b/src/main/java/alfio/manager/wallet/EventTicketClass.java new file mode 100644 index 0000000000..6873efc8da --- /dev/null +++ b/src/main/java/alfio/manager/wallet/EventTicketClass.java @@ -0,0 +1,154 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.wallet; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; + +@Builder +@Getter +public class EventTicketClass implements WalletEntity { + + public static final String WALLET_URL = "https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass"; + + private static final DateTimeFormatter EVENT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSX"); + + private String id; + + private String eventName; + + private String eventOrGroupingId; + + private String description; + + private String venue; + + private LatitudeLongitudePoint location; + + private String ticketType; + + private String logoUri; + + private ZonedDateTime start; + + private ZonedDateTime end; + + public String build(ObjectMapper mapper) { + ObjectNode object = mapper.createObjectNode(); + object.put("id", id); + object.put("eventId", eventOrGroupingId); + object.put("multipleDevicesAndHoldersAllowedStatus", "ONE_USER_ALL_DEVICES"); + object.put("issuerName", eventName); + object.set("eventName", + mapper.createObjectNode().set("defaultValue", mapper.createObjectNode() + .put("language", "en-US") + .put("value", ticketType))); + object.set("venue", + mapper.createObjectNode().setAll( + Map.of( + "name", mapper.createObjectNode().set("defaultValue", mapper.createObjectNode() + .put("language", "en-US") + .put("value", venue)), + "address", mapper.createObjectNode().set("defaultValue", mapper.createObjectNode() + .put("language", "en-US") + .put("value", venue)) + ))); + object.set("dateTime", + mapper.createObjectNode() + .put("start", start.format(EVENT_TIME_FORMATTER)) + .put("end", end.format(EVENT_TIME_FORMATTER))); + object.put("reviewStatus", "UNDER_REVIEW"); + object.put("hexBackgroundColor", "#FFFFFF"); + object.set("logo", + mapper.createObjectNode().set("sourceUri", mapper.createObjectNode() + .put("uri", logoUri))); + object.set("classTemplateInfo", + mapper.createObjectNode().set("cardTemplateOverride", + mapper.createObjectNode().set("cardRowTemplateInfos", + mapper.createArrayNode() + .add(mapper.createObjectNode().set("oneItem", + mapper.createObjectNode().setAll( + Map.of( + "item", mapper.createObjectNode().set("firstValue", + mapper.createObjectNode().set("fields", + mapper.createArrayNode() + .add(mapper.createObjectNode().put("fieldPath", "class.dateTime.start")))))))) + .add(mapper.createObjectNode().set("oneItem", + mapper.createObjectNode().setAll( + Map.of( + "item", mapper.createObjectNode().set("firstValue", + mapper.createObjectNode().set("fields", + mapper.createArrayNode() + .add(mapper.createObjectNode().put("fieldPath", "class.dateTime.end")))))))) + ))); + object.set("linksModuleData", + mapper.createObjectNode().set("uris", + mapper.createArrayNode() + .add(mapper.createObjectNode() + .put("uri", "https://alf.io") + .put("description", "Powered by Alf.io, the Open Source ticket reservation system.") + .put("id", "alfio"))) + ); + object.set("messages", mapper.createArrayNode() + .add(mapper.createObjectNode() + .put("header", "Event Description") + .put("body", description)) + ); + if (location != null) { + object.set("locations", location.accept(mapper)); + } + + try { + return mapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Getter + public static class LatitudeLongitudePoint { + private final Double latitude; + + private final Double longitude; + + private LatitudeLongitudePoint(Double latitude, Double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + public static LatitudeLongitudePoint of(Double latitude, Double longitude) { + return new LatitudeLongitudePoint(latitude, longitude); + } + + private ArrayNode accept(ObjectMapper mapper) { + return mapper.createArrayNode() + .add(mapper.createObjectNode() + .put("latitude", latitude) + .put("longitude", longitude) + ); + } + } +} diff --git a/src/main/java/alfio/manager/wallet/EventTicketObject.java b/src/main/java/alfio/manager/wallet/EventTicketObject.java new file mode 100644 index 0000000000..a20221913f --- /dev/null +++ b/src/main/java/alfio/manager/wallet/EventTicketObject.java @@ -0,0 +1,64 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.wallet; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.springframework.core.io.ByteArrayResource; + +import java.net.URI; +import java.time.format.DateTimeFormatter; + +@Builder +@Getter +public class EventTicketObject implements WalletEntity { + + public static final String WALLET_URL = "https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject"; + + private String id; + + private String classId; + + private String ticketHolderName; + + private String ticketNumber; + + private String barcode; + + public String build(ObjectMapper mapper) { + ObjectNode object = mapper.createObjectNode(); + object.put("id", id); + object.put("classId", classId); + object.put("state", "ACTIVE"); + object.put("ticketHolderName", ticketHolderName); + object.put("ticketNumber", ticketNumber); + object.set("barcode", mapper.createObjectNode() + .put("type", "QR_CODE") + .put("value", barcode)); + + try { + return mapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/alfio/manager/wallet/GoogleWalletException.java b/src/main/java/alfio/manager/wallet/GoogleWalletException.java new file mode 100644 index 0000000000..9e35d24257 --- /dev/null +++ b/src/main/java/alfio/manager/wallet/GoogleWalletException.java @@ -0,0 +1,29 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.wallet; + +public class GoogleWalletException extends RuntimeException { + + public GoogleWalletException(String message) { + super(message); + } + + public GoogleWalletException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/alfio/manager/wallet/GoogleWalletManager.java b/src/main/java/alfio/manager/wallet/GoogleWalletManager.java new file mode 100644 index 0000000000..e44def6b50 --- /dev/null +++ b/src/main/java/alfio/manager/wallet/GoogleWalletManager.java @@ -0,0 +1,349 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.wallet; + +import alfio.manager.system.ConfigurationManager; +import alfio.model.*; +import alfio.model.metadata.TicketMetadata; +import alfio.model.metadata.TicketMetadataContainer; +import alfio.model.system.ConfigurationKeys; +import alfio.model.system.command.InvalidateAccess; +import alfio.repository.*; +import alfio.util.HttpUtils; +import alfio.util.MustacheCustomTag; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.auth.oauth2.ServiceAccountCredentials; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.security.interfaces.RSAPrivateKey; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static alfio.config.Initializer.*; +import static alfio.model.system.ConfigurationKeys.*; + +@Component +@AllArgsConstructor +@Transactional +public class GoogleWalletManager { + + private static final Logger log = LoggerFactory.getLogger(GoogleWalletManager.class); + private static final String WALLET_OBJECT_ID = "gWalletObjectId"; + private static final String AUTHORIZATION = "Authorization"; + private static final String BEARER_PLACEHOLDER = "Bearer %s"; + private final EventRepository eventRepository; + private final ConfigurationManager configurationManager; + private final EventDescriptionRepository eventDescriptionRepository; + private final TicketCategoryRepository ticketCategoryRepository; + private final TicketRepository ticketRepository; + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + private final Environment environment; + private final AuditingRepository auditingRepository; + + public Optional> validateTicket(String eventName, String ticketUuid) { + var eventOptional = eventRepository.findOptionalEventAndOrganizationIdByShortName(eventName); + if (eventOptional.isEmpty()) { + log.trace("event {} not found", eventName); + return Optional.empty(); + } + + var event = eventOptional.get(); + return ticketRepository.findOptionalByUUID(ticketUuid) + .filter(t -> t.getEventId() == event.getId()) + .map(t -> Pair.of(event, t)); + } + + public String createAddToWalletUrl(Ticket ticket, EventAndOrganizationId event) { + Map passConf = getConfigurationKeys(event); + if (!passConf.isEmpty()) { + return buildWalletPassUrl(ticket, eventRepository.findById(event.getId()), passConf); + } else { + throw new GoogleWalletException("Google Wallet integration is not enabled."); + } + } + + @EventListener + public void invalidateAccessForTicket(InvalidateAccess invalidateAccess) { + try { + Map passConf = getConfigurationKeys(invalidateAccess.getEvent()); + if (!passConf.isEmpty()) { + invalidateAccess.getTicketMetadataContainer() + .getMetadataForKey(TicketMetadataContainer.GENERAL) + .map(m -> m.getAttributes().get(WALLET_OBJECT_ID)) + .ifPresent(s -> invalidateObject(invalidateAccess.getTicket().getUuid(), s, passConf)); + } + } catch (Exception e) { + log.warn("Error while invalidating access for ticket " + invalidateAccess.getTicket().getUuid(), e); + } + } + + private void invalidateObject(String ticketId, String objectId, Map passConf) { + try { + log.trace("Invalidating access to object ID: {}", objectId); + var credentials = retrieveCredentials(passConf.get(WALLET_SERVICE_ACCOUNT_KEY)); + URI uriWithId = URI.create(String.format("%s/%s", EventTicketObject.WALLET_URL, objectId)); + HttpRequest expireRequest = HttpRequest.newBuilder() + .uri(uriWithId) + .header(AUTHORIZATION, String.format(BEARER_PLACEHOLDER, credentials.refreshAccessToken().getTokenValue())) + .method("PATCH", HttpRequest.BodyPublishers.ofString("{\"state\":\"INACTIVE\"}")) + .build(); + var response = httpClient.send(expireRequest, HttpResponse.BodyHandlers.ofString()); + if (HttpUtils.callSuccessful(response)) { + log.debug("Access invalidated for ticket {}", ticketId); + } else { + logIfWarnEnabled(() -> log.warn("Cannot invalidate access for ticket {}, response: {}", ticketId, response.body())); + } + } catch (IOException e) { + throw new GoogleWalletException(e.getMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new GoogleWalletException(e.getMessage(), e); + } + } + + private Map getConfigurationKeys(EventAndOrganizationId event) { + var conf = configurationManager.getFor(Set.of( + ENABLE_WALLET, + WALLET_ISSUER_IDENTIFIER, + WALLET_SERVICE_ACCOUNT_KEY, + WALLET_OVERWRITE_PREVIOUS_CLASSES_AND_EVENTS, + BASE_URL), + event.getConfigurationLevel()); + + if (!conf.get(ENABLE_WALLET).getValueAsBooleanOrDefault()) { + return Map.of(); + } + var configValues = Map.of( + WALLET_ISSUER_IDENTIFIER, conf.get(WALLET_ISSUER_IDENTIFIER).getValue(), + WALLET_SERVICE_ACCOUNT_KEY, conf.get(WALLET_SERVICE_ACCOUNT_KEY).getValue(), + WALLET_OVERWRITE_PREVIOUS_CLASSES_AND_EVENTS, conf.get(WALLET_OVERWRITE_PREVIOUS_CLASSES_AND_EVENTS).getValue(), + BASE_URL, conf.get(BASE_URL).getValue()); + + if (configValues.values().stream().anyMatch(Optional::isEmpty)) { + return Map.of(); + } + + return configValues + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseThrow())); + } + + private String buildWalletPassUrl(Ticket ticket, + Event event, + Map config) { + String baseUrl = config.get(BASE_URL); + String issuerId = config.get(WALLET_ISSUER_IDENTIFIER); + String serviceAccountKey = config.get(WALLET_SERVICE_ACCOUNT_KEY); + boolean overwritePreviousClassesAndEvents = Boolean.parseBoolean(config.get(WALLET_OVERWRITE_PREVIOUS_CLASSES_AND_EVENTS)); + + String eventDescription = MustacheCustomTag.renderToTextCommonmark( + eventDescriptionRepository.findDescriptionByEventIdTypeAndLocale(event.getId(), EventDescription.EventDescriptionType.DESCRIPTION, ticket.getUserLanguage()).orElse("")); + TicketCategory category = ticketCategoryRepository.getById(ticket.getCategoryId()); + var ticketValidityStart = Optional.ofNullable(category.getTicketValidityStart(event.getZoneId())).orElse(event.getBegin()); + var ticketValidityEnd = Optional.ofNullable(category.getTicketValidityEnd(event.getZoneId())).orElse(event.getEnd()); + + EventTicketClass.LatitudeLongitudePoint latitudeLongitudePoint = null; + if (event.getLatitude() != null && event.getLongitude() != null) { + latitudeLongitudePoint = EventTicketClass.LatitudeLongitudePoint.of(Double.parseDouble(event.getLatitude()), Double.parseDouble(event.getLongitude())); + } + + var host = URI.create(baseUrl).getHost().replace(".", "-"); + var eventTicketClass = EventTicketClass.builder() + .id(formatEventTicketClassId(event, issuerId, category, host)) + .eventOrGroupingId(Integer.toString(event.getId())) + .logoUri(baseUrl + "/file/" + event.getFileBlobId()) + .eventName(event.getDisplayName()) + .description(eventDescription) + .venue(event.getLocation()) + .location(latitudeLongitudePoint) + .ticketType(category.getName()) + .start(ticketValidityStart) + .end(ticketValidityEnd) + .build(); + + String walletTicketId = formatEventTicketObjectId(ticket, event, issuerId, host); + var eventTicketObject = EventTicketObject.builder() + .id(walletTicketId) + .classId(eventTicketClass.getId()) + .ticketHolderName(ticket.getFullName()) + .ticketNumber(ticket.getUuid()) + .barcode(ticket.ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive())) + .build(); + + GoogleCredentials credentials = retrieveCredentials(serviceAccountKey); + + createEventClass(credentials, eventTicketClass, overwritePreviousClassesAndEvents); + String eventObjectId = createEventObject(credentials, eventTicketObject, overwritePreviousClassesAndEvents); + String walletPassUrl = generateWalletPassUrl(credentials, eventObjectId, baseUrl); + persistPassId(ticket, eventObjectId); + return walletPassUrl; + } + + private static GoogleCredentials retrieveCredentials(String serviceAccountKey) { + try { + return GoogleCredentials + .fromStream(new ByteArrayInputStream(serviceAccountKey.getBytes(StandardCharsets.UTF_8))) + .createScoped(Collections.singleton("https://www.googleapis.com/auth/wallet_object.issuer")); + } catch (IOException e) { + throw new GoogleWalletException("Unable to retrieve Service Account Credentials from configuration", e); + } + } + + private void persistPassId(Ticket ticket, String eventObjectId) { + var metadataContainer = ticketRepository.getTicketMetadata(ticket.getId()); + var existingMetadata = metadataContainer.getMetadataForKey(TicketMetadataContainer.GENERAL); + var attributesMap = existingMetadata.map(ticketMetadata -> new HashMap<>(ticketMetadata.getAttributes())) + .orElseGet(HashMap::new); + attributesMap.put(WALLET_OBJECT_ID, eventObjectId); + metadataContainer.putMetadata(TicketMetadataContainer.GENERAL, existingMetadata.map(tm -> tm.withAttributes(attributesMap)).orElseGet(() -> new TicketMetadata(null, null, attributesMap))); + ticketRepository.updateTicketMetadata(ticket.getId(), metadataContainer); + } + + private String formatEventTicketObjectId(Ticket ticket, Event event, String issuerId, String host) { + return String.format("%s.%s-%s-object.%s-%s", + issuerId, + walletIdPrefix(), + host, + event.getShortName().replaceAll("[^\\w.-]", "_"), + // if the attendee gives their ticket to somebody else, the new ticket holder must be able to add their ticket to the wallet + // therefore we add count(audit(UPDATE_TICKET)) as suffix for the ticket UUID + ticket.getUuid()+ "_" + auditingRepository.countAuditsOfTypeForTicket(ticket.getTicketsReservationId(), ticket.getId(), Audit.EventType.UPDATE_TICKET)); + } + + private String formatEventTicketClassId(Event event, String issuerId, TicketCategory category, String host) { + return String.format("%s.%s-%s-class.%s-%d", issuerId, walletIdPrefix(), host, event.getShortName().replaceAll("[^\\w.-]", "_"), category.getId()); + } + + private String generateWalletPassUrl(GoogleCredentials credentials, String eventObjectId, String url) { + var objectIdMap = Map.of("id", eventObjectId); + var payload = Map.of("genericObjects", List.of(objectIdMap)); + var claims = Map.of( + "iss", ((ServiceAccountCredentials) credentials).getClientEmail(), + "aud", "google", + "origins", List.of(url), + "typ", "savetowallet", + "payload", payload + ); + + Algorithm algorithm = Algorithm.RSA256( + null, + (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create() + .withPayload(claims) + .sign(algorithm); + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + + private String createEventClass(GoogleCredentials credentials, EventTicketClass eventTicketClass, boolean overwritePreviousClassesAndEvents) { + return createOnWallet(EventTicketClass.WALLET_URL, credentials, eventTicketClass, overwritePreviousClassesAndEvents); + } + + private String createEventObject(GoogleCredentials credentials, EventTicketObject eventTicketObject, boolean overwritePreviousClassesAndEvents) { + return createOnWallet(EventTicketObject.WALLET_URL, credentials, eventTicketObject, overwritePreviousClassesAndEvents); + } + + private String createOnWallet(String uri, GoogleCredentials credentials, WalletEntity entity, boolean overwritePreviousClassesAndEvents) { + try { + URI uriWithId = URI.create(String.format("%s/%s", uri, entity.getId())); + HttpRequest getRequest = HttpRequest.newBuilder() + .uri(uriWithId) + .header(AUTHORIZATION, String.format(BEARER_PLACEHOLDER, credentials.refreshAccessToken().getTokenValue())) + .GET() + .build(); + log.debug("GET Request: {}", getRequest); + + HttpResponse getResponse = httpClient.send(getRequest, HttpResponse.BodyHandlers.ofString()); + log.debug("GET Response: {}", getResponse); + if (getResponse.statusCode() != 200 && getResponse.statusCode() != 404) { + logIfWarnEnabled(() -> log.warn("Received {} status code when creating entity but 200 or 404 were expected: {}", getResponse.statusCode(), getResponse.body())); + throw new GoogleWalletException("Cannot create Wallet class. Response status: " + getResponse.statusCode()); + } + + if (getResponse.statusCode() == 404 || overwritePreviousClassesAndEvents) { + HttpRequest.Builder builder = HttpRequest.newBuilder() + .header(AUTHORIZATION, String.format(BEARER_PLACEHOLDER, credentials.refreshAccessToken().getTokenValue())); + if (getResponse.statusCode() == 404) { + builder = builder + .uri(URI.create(uri)) + .POST(HttpRequest.BodyPublishers.ofString(entity.build(objectMapper))); + } else { + builder = builder + .uri(uriWithId) + .PUT(HttpRequest.BodyPublishers.ofString(entity.build(objectMapper))); + } + HttpRequest postOrPutRequest = builder.build(); + log.debug("POST or PUT Request: {}", postOrPutRequest); + HttpResponse postOrPutResponse = httpClient.send(postOrPutRequest, HttpResponse.BodyHandlers.ofString()); + log.debug("POST or PUT Response: {}", postOrPutResponse); + if (postOrPutResponse.statusCode() != 200) { + logIfWarnEnabled(() -> log.warn("Received {} status code when creating entity: {}", postOrPutResponse.statusCode(), postOrPutResponse.body())); + throw new GoogleWalletException("Cannot create wallet. Response status: " + postOrPutResponse.statusCode()); + } + } + return entity.getId(); + } catch (IOException e) { + throw new GoogleWalletException("Error while communicating with the Google Wallet API", e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new GoogleWalletException("Error while communicating with the Google Wallet API", e); + } + } + + private String walletIdPrefix() { + var profile = Stream.of(PROFILE_DEMO, PROFILE_DEV, PROFILE_LIVE) + .filter(p -> environment.acceptsProfiles(Profiles.of(p))) + .findFirst() + .orElseThrow(() -> new NoSuchElementException("No suitable Spring Profile found to create a Wallet ID prefix for classes and objects. Must have one of PROFILE_DEMO, PROFILE_DEV, or PROFILE_LIVE")); + if (profile.equals(PROFILE_LIVE)) { + return "live"; + } + return profile; + } + + private void logIfWarnEnabled(ConditionalLogger logger) { + if (log.isWarnEnabled()) { + logger.log(); + } + } + + @FunctionalInterface + private interface ConditionalLogger { + void log(); + } + +} diff --git a/src/main/java/alfio/manager/wallet/WalletEntity.java b/src/main/java/alfio/manager/wallet/WalletEntity.java new file mode 100644 index 0000000000..54be6e4567 --- /dev/null +++ b/src/main/java/alfio/manager/wallet/WalletEntity.java @@ -0,0 +1,27 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.wallet; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public interface WalletEntity { + + public String getId(); + + public String build(ObjectMapper mapper); + +} diff --git a/src/main/java/alfio/model/AdditionalService.java b/src/main/java/alfio/model/AdditionalService.java index fa95ebe8ea..f4f1fe7198 100644 --- a/src/main/java/alfio/model/AdditionalService.java +++ b/src/main/java/alfio/model/AdditionalService.java @@ -147,17 +147,12 @@ public String getChecksum() { } public static PriceContainer.VatStatus getVatStatus(VatType vatType, PriceContainer.VatStatus eventVatStatus) { - switch (vatType) { - case INHERITED: - return eventVatStatus; - case NONE: - return PriceContainer.VatStatus.NONE; - case CUSTOM_EXCLUDED: - return PriceContainer.VatStatus.NOT_INCLUDED; - case CUSTOM_INCLUDED: - return PriceContainer.VatStatus.INCLUDED; - default: - return PriceContainer.VatStatus.NOT_INCLUDED; - } + return switch (vatType) { + case INHERITED -> eventVatStatus; + case NONE -> PriceContainer.VatStatus.NONE; + case CUSTOM_EXCLUDED -> PriceContainer.VatStatus.NOT_INCLUDED; + case CUSTOM_INCLUDED -> PriceContainer.VatStatus.INCLUDED; + default -> PriceContainer.VatStatus.NOT_INCLUDED; + }; } } diff --git a/src/main/java/alfio/model/AdditionalServiceItem.java b/src/main/java/alfio/model/AdditionalServiceItem.java index c556a151f4..4f587a11de 100644 --- a/src/main/java/alfio/model/AdditionalServiceItem.java +++ b/src/main/java/alfio/model/AdditionalServiceItem.java @@ -24,8 +24,13 @@ @Getter public class AdditionalServiceItem { + // are considered "Confirmed": ACQUIRED, CHECKED_IN and TO_BE_PAID public enum AdditionalServiceItemStatus { - FREE, PENDING, TO_BE_PAID, ACQUIRED, CANCELLED, CHECKED_IN, EXPIRED, INVALIDATED, RELEASED + FREE, // <- unused + PENDING, TO_BE_PAID, ACQUIRED, CANCELLED, + CHECKED_IN, // <- unused + EXPIRED, + INVALIDATED, RELEASED // <- both unused } private final int id; diff --git a/src/main/java/alfio/model/AdditionalServiceItemExport.java b/src/main/java/alfio/model/AdditionalServiceItemExport.java index aa35631554..3ec4005948 100644 --- a/src/main/java/alfio/model/AdditionalServiceItemExport.java +++ b/src/main/java/alfio/model/AdditionalServiceItemExport.java @@ -32,6 +32,9 @@ public class AdditionalServiceItemExport { private final String emailAddress; private final String additionalServiceTitle; private final AdditionalService.AdditionalServiceType additionalServiceType; + + private final AdditionalServiceItem.AdditionalServiceItemStatus additionalServiceItemStatus; + private final Integer finalPriceCts; private final String currencyCode; private final Integer vatCts; @@ -49,7 +52,8 @@ public AdditionalServiceItemExport(@Column("ai_uuid") String uuid, @Column("ai_final_price_cts") Integer finalPriceCts, @Column("ai_currency_code") String currencyCode, @Column("ai_vat_cts") Integer vatCts, - @Column("ai_discount_cts") Integer discountCts) { + @Column("ai_discount_cts") Integer discountCts, + @Column("ai_status") AdditionalServiceItem.AdditionalServiceItemStatus additionalServiceItemStatus) { this.uuid = uuid; this.utcCreation = utcCreation; this.utcLastModified = utcLastModified; @@ -63,5 +67,6 @@ public AdditionalServiceItemExport(@Column("ai_uuid") String uuid, this.currencyCode = currencyCode; this.vatCts = vatCts; this.discountCts = discountCts; + this.additionalServiceItemStatus = additionalServiceItemStatus; } } diff --git a/src/main/java/alfio/model/AdditionalServiceText.java b/src/main/java/alfio/model/AdditionalServiceText.java index e065c45909..6ba733676b 100644 --- a/src/main/java/alfio/model/AdditionalServiceText.java +++ b/src/main/java/alfio/model/AdditionalServiceText.java @@ -17,31 +17,14 @@ package alfio.model; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class AdditionalServiceText { +public record AdditionalServiceText(@Column("id") int id, + @Column("additional_service_id_fk") Integer additionalServiceId, + @Column("locale") String locale, + @Column("type") TextType type, + @Column("value") String value) { public enum TextType { TITLE, DESCRIPTION } - - private final int id; - private final Integer additionalServiceId; - private final String locale; - private final TextType type; - private final String value; - - public AdditionalServiceText(@Column("id") int id, - @Column("additional_service_id_fk") Integer additionalServiceId, - @Column("locale") String locale, - @Column("type") TextType type, - @Column("value") String value) { - this.id = id; - this.additionalServiceId = additionalServiceId; - this.locale = locale; - this.type = type; - this.value = value; - } - } diff --git a/src/main/java/alfio/model/AdminReservationRequestStats.java b/src/main/java/alfio/model/AdminReservationRequestStats.java index 4b9b7c985c..4e85e13fbe 100644 --- a/src/main/java/alfio/model/AdminReservationRequestStats.java +++ b/src/main/java/alfio/model/AdminReservationRequestStats.java @@ -17,30 +17,11 @@ package alfio.model; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class AdminReservationRequestStats { - - private final String requestId; - private final long userId; - private final long eventId; - private final int countSuccess; - private final int countPending; - private final int countError; - - - public AdminReservationRequestStats(@Column("request_id") String requestId, - @Column("user_id") long userId, - @Column("event_id") long eventId, - @Column("count_success") int countSuccess, - @Column("count_pending") int countPending, - @Column("count_error") int countError) { - this.requestId = requestId; - this.userId = userId; - this.eventId = eventId; - this.countSuccess = countSuccess; - this.countPending = countPending; - this.countError = countError; - } +public record AdminReservationRequestStats(@Column("request_id") String requestId, + @Column("user_id") long userId, + @Column("event_id") long eventId, + @Column("count_success") int countSuccess, + @Column("count_pending") int countPending, + @Column("count_error") int countError) { } diff --git a/src/main/java/alfio/model/AllocationStatus.java b/src/main/java/alfio/model/AllocationStatus.java index bfdd9742a1..f2547ea7b4 100644 --- a/src/main/java/alfio/model/AllocationStatus.java +++ b/src/main/java/alfio/model/AllocationStatus.java @@ -19,5 +19,5 @@ public enum AllocationStatus { FREE, PRE_RESERVED, PENDING, TO_BE_PAID, ACQUIRED, CANCELLED, CHECKED_IN, EXPIRED, - INVALIDATED, RELEASED; + INVALIDATED, RELEASED } diff --git a/src/main/java/alfio/model/Audit.java b/src/main/java/alfio/model/Audit.java index 39dc074a0d..bcdf4b3c85 100644 --- a/src/main/java/alfio/model/Audit.java +++ b/src/main/java/alfio/model/Audit.java @@ -63,6 +63,7 @@ public enum EventType { VAT_VALIDATION_SUCCESSFUL, VAT_FORMAL_VALIDATION_SUCCESSFUL, VAT_VALIDATION_SKIPPED, + VAT_CUSTOM_CONFIGURATION_APPLIED, GROUP_MEMBER_ACQUIRED, CREDIT_NOTE_ISSUED, BILLING_DATA_UPDATED, @@ -102,7 +103,8 @@ public Audit(@Column("reservation_id") String reservationId, @Column("event_type this.eventTime = eventTime; this.entityType = entityType; this.entityId = entityId; - this.modifications = modifications == null ? null : Json.fromJson(modifications, new TypeReference>>() {}); + this.modifications = modifications == null ? null : Json.fromJson(modifications, new TypeReference<>() { + }); this.username = username; this.firstName = firstName; this.lastName = lastName; diff --git a/src/main/java/alfio/model/BookedAdditionalService.java b/src/main/java/alfio/model/BookedAdditionalService.java index f58414dffa..6f3e26e5e0 100644 --- a/src/main/java/alfio/model/BookedAdditionalService.java +++ b/src/main/java/alfio/model/BookedAdditionalService.java @@ -17,20 +17,8 @@ package alfio.model; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class BookedAdditionalService { - - private final String additionalServiceName; - private final int additionalServiceId; - private final int count; - - public BookedAdditionalService(@Column("as_name") String additionalServiceName, - @Column("as_id") int additionalServiceId, - @Column("qty") int count) { - this.additionalServiceName = additionalServiceName; - this.additionalServiceId = additionalServiceId; - this.count = count; - } +public record BookedAdditionalService(@Column("as_name") String additionalServiceName, + @Column("as_id") int additionalServiceId, + @Column("qty") int count) { } diff --git a/src/main/java/alfio/model/Configurable.java b/src/main/java/alfio/model/Configurable.java index e6a5186e4a..5347b741e4 100644 --- a/src/main/java/alfio/model/Configurable.java +++ b/src/main/java/alfio/model/Configurable.java @@ -26,4 +26,6 @@ public interface Configurable { @JsonIgnore ConfigurationLevel getConfigurationLevel(); + + int getOrganizationId(); } diff --git a/src/main/java/alfio/model/ContentLanguage.java b/src/main/java/alfio/model/ContentLanguage.java index 4e5324c818..b405557420 100644 --- a/src/main/java/alfio/model/ContentLanguage.java +++ b/src/main/java/alfio/model/ContentLanguage.java @@ -17,13 +17,12 @@ package alfio.model; import alfio.util.LocaleUtil; -import lombok.EqualsAndHashCode; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.stream.Collectors; -@EqualsAndHashCode public class ContentLanguage { public static final int ENGLISH_IDENTIFIER = 0b00010; @@ -75,4 +74,17 @@ public Locale getLocale() { public int getValue() { return value; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContentLanguage that = (ContentLanguage) o; + return value == that.value && Objects.equals(locale, that.locale) && Objects.equals(displayLocale, that.displayLocale); + } + + @Override + public int hashCode() { + return Objects.hash(locale, value, displayLocale); + } } diff --git a/src/main/java/alfio/model/DetailedScanData.java b/src/main/java/alfio/model/DetailedScanData.java index 339134ed17..0653d741fa 100644 --- a/src/main/java/alfio/model/DetailedScanData.java +++ b/src/main/java/alfio/model/DetailedScanData.java @@ -60,12 +60,13 @@ public DetailedScanData(@Column("t_id") int ticketId, @Column("s_event_id") int scanEventId, @Column("s_ticket_id") int scanTicketId, @Column("s_notes") String notes, - @Column("s_lead_status") SponsorScan.LeadStatus leadStatus) { + @Column("s_lead_status") SponsorScan.LeadStatus leadStatus, + @Column("s_operator") String operator) { this.ticket = new Ticket(ticketId, ticketUuid, ticketCreation, ticketCategoryId, ticketStatus, ticketEventId, ticketsReservationId, ticketFullName, ticketFirstName, ticketLastName, ticketEmail, ticketLockedAssignment, ticketUserLanguage, ticketSrcPriceCts, ticketFinalPriceCts, ticketVatCts, ticketDiscountCts, extReference, currencyCode, ticketTags, ticketSubscriptionId, ticketVatStatus); - this.sponsorScan = new SponsorScan(scanUserId, scanTimestamp, scanEventId, scanTicketId, notes, leadStatus); + this.sponsorScan = new SponsorScan(scanUserId, scanTimestamp, scanEventId, scanTicketId, notes, leadStatus, operator); } } diff --git a/src/main/java/alfio/model/EmailMessage.java b/src/main/java/alfio/model/EmailMessage.java index 3601ae3cdb..1e3e21284e 100644 --- a/src/main/java/alfio/model/EmailMessage.java +++ b/src/main/java/alfio/model/EmailMessage.java @@ -106,13 +106,12 @@ public int compareTo(EmailMessage o) { @Override public boolean equals(Object obj) { - if(!(obj instanceof EmailMessage)) { + if(!(obj instanceof EmailMessage other)) { return false; } if(obj == this) { return true; } - EmailMessage other = (EmailMessage)obj; return new EqualsBuilder() .append(eventId, other.eventId) .append(subscriptionDescriptorId, other.subscriptionDescriptorId) diff --git a/src/main/java/alfio/model/EntityIdAndMetadata.java b/src/main/java/alfio/model/EntityIdAndMetadata.java index 7cba8e1b7d..cf41a4b3e9 100644 --- a/src/main/java/alfio/model/EntityIdAndMetadata.java +++ b/src/main/java/alfio/model/EntityIdAndMetadata.java @@ -19,16 +19,7 @@ import alfio.model.metadata.AlfioMetadata; import alfio.model.support.JSONData; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class EntityIdAndMetadata { - private final Integer id; - private final AlfioMetadata metadata; - - public EntityIdAndMetadata(@Column("id") Integer id, - @Column("metadata") @JSONData AlfioMetadata metadata) { - this.id = id; - this.metadata = metadata; - } +public record EntityIdAndMetadata(@Column("id") Integer id, + @Column("metadata") @JSONData AlfioMetadata metadata) { } diff --git a/src/main/java/alfio/model/Event.java b/src/main/java/alfio/model/Event.java index 2f8c464af5..251df828cb 100644 --- a/src/main/java/alfio/model/Event.java +++ b/src/main/java/alfio/model/Event.java @@ -18,11 +18,11 @@ import alfio.model.transaction.PaymentProxy; import alfio.util.ClockProvider; +import alfio.util.EventUtil; import alfio.util.MonetaryUtil; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.flywaydb.core.api.MigrationVersion; @@ -37,7 +37,6 @@ import static java.time.temporal.ChronoField.OFFSET_SECONDS; @Getter -@Log4j2 public class Event extends EventAndOrganizationId implements EventHiddenFieldContainer, EventCheckInInfo, PurchaseContext { private static final String VERSION_FOR_FIRST_AND_LAST_NAME = "15.1.8.8"; @@ -254,6 +253,10 @@ public boolean mustUseFirstAndLastName() { return mustUseFirstAndLastName(this); } + public boolean supportsQRCodeCaseInsensitive() { + return EventUtil.supportsCaseInsensitiveQRCode(version); + } + private static boolean mustUseFirstAndLastName(Event event) { return event.getVersion() != null diff --git a/src/main/java/alfio/model/EventCheckInInfo.java b/src/main/java/alfio/model/EventCheckInInfo.java index 4c457386b4..27385c50ba 100644 --- a/src/main/java/alfio/model/EventCheckInInfo.java +++ b/src/main/java/alfio/model/EventCheckInInfo.java @@ -16,14 +16,21 @@ */ package alfio.model; +import com.fasterxml.jackson.annotation.JsonIgnore; + import java.time.ZonedDateTime; public interface EventCheckInInfo extends TimeZoneInfo { + String VERSION_FOR_CODE_CASE_INSENSITIVE = "205.2.0.0.50"; + int getId(); String getPrivateKey(); ZonedDateTime getBegin(); ZonedDateTime getEnd(); Event.EventFormat getFormat(); + @JsonIgnore + boolean supportsQRCodeCaseInsensitive(); + } diff --git a/src/main/java/alfio/model/EventDescription.java b/src/main/java/alfio/model/EventDescription.java index a6bdaa2516..226a09a203 100644 --- a/src/main/java/alfio/model/EventDescription.java +++ b/src/main/java/alfio/model/EventDescription.java @@ -17,38 +17,17 @@ package alfio.model; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class EventDescription { + +public record EventDescription(@Column("event_id_fk") Integer eventId, @Column("locale") String locale, + @Column("type") EventDescriptionType eventDescriptionType, + @Column("description") String description) { // public enum EventDescriptionType { DESCRIPTION } - private final Integer eventId; - private final String locale; - private final EventDescriptionType eventDescriptionType; - private final String description; - - public EventDescription(@Column("event_id_fk") Integer eventId, @Column("locale") String locale, - @Column("type") EventDescriptionType eventDescriptionType, - @Column("description") String description) { - this.eventId = eventId; - this.locale = locale; - this.eventDescriptionType = eventDescriptionType; - this.description = description; - } - - @Getter - public static class LocaleDescription { - private final String locale; - private final String description; - - public LocaleDescription(@Column("locale") String locale, @Column("description") String description) { - this.locale = locale; - this.description = description; - } + public record LocaleDescription(@Column("locale") String locale, @Column("description") String description) { } } diff --git a/src/main/java/alfio/model/EventWithAdditionalInfo.java b/src/main/java/alfio/model/EventWithAdditionalInfo.java index 0b979b995f..6eec3e4f1d 100644 --- a/src/main/java/alfio/model/EventWithAdditionalInfo.java +++ b/src/main/java/alfio/model/EventWithAdditionalInfo.java @@ -16,18 +16,15 @@ */ package alfio.model; -import alfio.manager.support.extension.ExtensionCapability; import alfio.model.metadata.AlfioMetadata; import alfio.model.modification.StatisticsContainer; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.experimental.Delegate; import java.math.BigDecimal; import java.util.*; -@AllArgsConstructor @Getter public class EventWithAdditionalInfo implements StatisticsContainer, PriceContainer { @@ -49,6 +46,24 @@ public class EventWithAdditionalInfo implements StatisticsContainer, PriceContai private final Set supportedCapabilities; + public EventWithAdditionalInfo(Event event, + List ticketCategories, + EventStatistic eventStatistic, + Map description, + BigDecimal grossIncome, + AlfioMetadata metadata, + List linkedSubscriptions, + Set supportedCapabilities) { + this.event = event; + this.ticketCategories = ticketCategories; + this.eventStatistic = eventStatistic; + this.description = description; + this.grossIncome = grossIncome; + this.metadata = metadata; + this.linkedSubscriptions = linkedSubscriptions; + this.supportedCapabilities = supportedCapabilities; + } + @JsonIgnore public Event getEvent() { return event; diff --git a/src/main/java/alfio/model/ExtensionSupport.java b/src/main/java/alfio/model/ExtensionSupport.java index 507f6a4da5..ba15f637bf 100644 --- a/src/main/java/alfio/model/ExtensionSupport.java +++ b/src/main/java/alfio/model/ExtensionSupport.java @@ -19,7 +19,8 @@ import alfio.extension.ExtensionMetadata; import alfio.model.support.JSONData; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @Getter @@ -143,11 +144,17 @@ public String getConfigurationPathLevel() { } } - @AllArgsConstructor + @Getter public static class ExtensionMetadataValue { private final int id; private final String value; + + @JsonCreator + public ExtensionMetadataValue(@JsonProperty("id") int id, @JsonProperty("value") String value) { + this.id = id; + this.value = value; + } } diff --git a/src/main/java/alfio/model/OrderSummary.java b/src/main/java/alfio/model/OrderSummary.java index d171adf315..12d58dafcf 100644 --- a/src/main/java/alfio/model/OrderSummary.java +++ b/src/main/java/alfio/model/OrderSummary.java @@ -19,9 +19,12 @@ import alfio.util.MonetaryUtil; import lombok.Data; +import java.math.BigDecimal; import java.util.List; import java.util.stream.Collectors; +import static alfio.util.MonetaryUtil.*; + @Data public class OrderSummary { private final TotalPrice originalTotalPrice; @@ -54,8 +57,8 @@ public boolean getNotYetPaid() { } public int getTicketAmount() { - return summary.stream().filter(s-> SummaryRow.SummaryType.TICKET == s.getType()) - .mapToInt(SummaryRow::getAmount) + return summary.stream().filter(s-> SummaryRow.SummaryType.TICKET == s.type()) + .mapToInt(SummaryRow::amount) .sum(); } @@ -63,7 +66,7 @@ public List getSummary() { //filter out the promotions code that have been inserted in the order but not used return summary.stream() - .filter(s-> !(s.isDiscount() && s.getAmount() == 0)) + .filter(s-> !(s.isDiscount() && s.amount() == 0)) .collect(Collectors.toList()); } @@ -87,18 +90,29 @@ public String getTotalNetPrice() { if(free) { return null; } - return MonetaryUtil.formatCents(originalTotalPrice.getPriceWithVAT() - originalTotalPrice.getVAT(), originalTotalPrice.getCurrencyCode());// FIXME can be null + return MonetaryUtil.formatCents(originalTotalPrice.priceWithVAT() - originalTotalPrice.VAT(), originalTotalPrice.currencyCode());// FIXME can be null } public int getPriceInCents() { - return originalTotalPrice.getPriceWithVAT(); + return originalTotalPrice.priceWithVAT(); } public String getDescriptionForPayment() { - return summary.stream().filter(r -> !r.isDiscount()).map(SummaryRow::getDescriptionForPayment).collect(Collectors.joining(", ")); + return summary.stream().filter(r -> !r.isDiscount() && !r.getTaxDetail()) + .map(SummaryRow::getDescriptionForPayment).collect(Collectors.joining(", ")); } public boolean getDisplaySplitPaymentNote() { return !free && (vatStatus == PriceContainer.VatStatus.INCLUDED_NOT_CHARGED || vatStatus == PriceContainer.VatStatus.NOT_INCLUDED_NOT_CHARGED); } + + public String getPriceBeforeTaxes() { + String currencyCode = originalTotalPrice.currencyCode(); + if(PriceContainer.VatStatus.isVatIncluded(vatStatus)) { + var vat = vatStatus.extractVat(centsToUnit(originalTotalPrice.priceWithVAT(), currencyCode), new BigDecimal(vatPercentage)); + return formatUnit(new BigDecimal(getTotalPrice()).subtract(vat), currencyCode); + } else { + return formatCents(originalTotalPrice.priceWithVAT() - originalTotalPrice.VAT(), currencyCode); + } + } } diff --git a/src/main/java/alfio/model/PaymentInformation.java b/src/main/java/alfio/model/PaymentInformation.java index c400564049..10ddf7aea7 100644 --- a/src/main/java/alfio/model/PaymentInformation.java +++ b/src/main/java/alfio/model/PaymentInformation.java @@ -16,18 +16,23 @@ */ package alfio.model; -import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @Getter -@AllArgsConstructor public class PaymentInformation { private final String paidAmount; private final String refundedAmount; private final String fee; private final String platformFee; + public PaymentInformation(String paidAmount, String refundedAmount, String fee, String platformFee) { + this.paidAmount = paidAmount; + this.refundedAmount = refundedAmount; + this.fee = fee; + this.platformFee = platformFee; + } + public boolean isFullyRefunded() { return StringUtils.equals(paidAmount, refundedAmount); } diff --git a/src/main/java/alfio/model/PriceContainer.java b/src/main/java/alfio/model/PriceContainer.java index 129ebf5df4..de23c34043 100644 --- a/src/main/java/alfio/model/PriceContainer.java +++ b/src/main/java/alfio/model/PriceContainer.java @@ -39,6 +39,9 @@ enum VatStatus { NOT_INCLUDED(notIncludedVatCalculator, UnaryOperator.identity()), INCLUDED_EXEMPT(includedVatExtractor, BigDecimal::negate), NOT_INCLUDED_EXEMPT((price, vatPercentage) -> BigDecimal.ZERO, UnaryOperator.identity()), + // tax exemption was granted by custom rules (extension CUSTOM_TAX_POLICY_APPLICATION) + CUSTOM_INCLUDED_EXEMPT(includedVatExtractor, BigDecimal::negate), + CUSTOM_NOT_INCLUDED_EXEMPT((price, vatPercentage) -> BigDecimal.ZERO, UnaryOperator.identity()), // The following two are dedicated for handling italian-specific cases, "split payment" // VAT has to be shown on the invoice, but not charged INCLUDED_NOT_CHARGED(includedVatExtractor, UnaryOperator.identity()), @@ -62,11 +65,19 @@ public BigDecimal extractRawVAT(BigDecimal price, BigDecimal vatPercentage) { } public static boolean isVatExempt(VatStatus vatStatus) { - return vatStatus == INCLUDED_EXEMPT || vatStatus == NOT_INCLUDED_EXEMPT; + return vatStatus == INCLUDED_EXEMPT || vatStatus == NOT_INCLUDED_EXEMPT + || vatStatus == CUSTOM_INCLUDED_EXEMPT || vatStatus == CUSTOM_NOT_INCLUDED_EXEMPT; } public static boolean isVatIncluded(VatStatus vatStatus) { - return vatStatus == INCLUDED || vatStatus == INCLUDED_EXEMPT; + return vatStatus == INCLUDED || vatStatus == INCLUDED_EXEMPT || vatStatus == CUSTOM_INCLUDED_EXEMPT; + } + + public static VatStatus forceExempt(VatStatus original) { + if (isVatIncluded(original)) { + return INCLUDED_EXEMPT; + } + return NOT_INCLUDED_EXEMPT; } } @@ -122,15 +133,11 @@ default BigDecimal getFinalPrice() { } final BigDecimal price = centsToUnit(getSrcPriceCts(), getCurrencyCode()); BigDecimal discountedPrice = price.subtract(getAppliedDiscount()); - switch(vatStatus) { - case INCLUDED: - case NOT_INCLUDED_NOT_CHARGED: - return discountedPrice; - case INCLUDED_NOT_CHARGED: - return discountedPrice.subtract(getVAT()); - default: - return discountedPrice.add(getVAT()); - } + return switch (vatStatus) { + case INCLUDED, NOT_INCLUDED_NOT_CHARGED -> discountedPrice; + case INCLUDED_NOT_CHARGED -> discountedPrice.subtract(getVAT()); + default -> discountedPrice.add(getVAT()); + }; } /** @@ -157,8 +164,8 @@ default BigDecimal getVAT() { @JsonIgnore default BigDecimal getAppliedDiscount() { return getDiscount() - // do not take into account reservation-level discount - .filter(discount -> discount.getDiscountType() != PromoCodeDiscount.DiscountType.FIXED_AMOUNT_RESERVATION) + // do not take into account reservation-level discount or access codes + .filter(discount -> discount.getDiscountType() != PromoCodeDiscount.DiscountType.FIXED_AMOUNT_RESERVATION && discount.getCodeType() != PromoCodeDiscount.CodeType.ACCESS) .map(discount -> { String currencyCode = getCurrencyCode(); final BigDecimal price = centsToUnit(getSrcPriceCts(), currencyCode); @@ -176,9 +183,9 @@ default BigDecimal getAppliedDiscount() { default BigDecimal getNetPrice() { var vatStatus = getVatStatus(); var currencyCode = getCurrencyCode(); - if(vatStatus == VatStatus.NOT_INCLUDED_EXEMPT) { + if(vatStatus == VatStatus.NOT_INCLUDED_EXEMPT || vatStatus == VatStatus.CUSTOM_NOT_INCLUDED_EXEMPT) { return MonetaryUtil.centsToUnit(getSrcPriceCts(), currencyCode); - } else if(vatStatus == VatStatus.INCLUDED_EXEMPT) { + } else if(vatStatus == VatStatus.INCLUDED_EXEMPT || vatStatus == VatStatus.CUSTOM_INCLUDED_EXEMPT) { var rawVat = vatStatus.extractRawVAT(centsToUnit(getSrcPriceCts(), getCurrencyCode()), getVatPercentageOrZero()); return MonetaryUtil.centsToUnit(getSrcPriceCts(), currencyCode).add(rawVat); } else if(vatStatus == VatStatus.INCLUDED || vatStatus == VatStatus.INCLUDED_NOT_CHARGED) { diff --git a/src/main/java/alfio/model/PromoCodeDiscount.java b/src/main/java/alfio/model/PromoCodeDiscount.java index 6e89079c0b..18505bbcb1 100644 --- a/src/main/java/alfio/model/PromoCodeDiscount.java +++ b/src/main/java/alfio/model/PromoCodeDiscount.java @@ -22,6 +22,7 @@ import com.google.gson.reflect.TypeToken; import lombok.Getter; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -61,6 +62,7 @@ public static boolean isFixedAmount(DiscountType discountType) { private final String emailReference; private final CodeType codeType; private final Integer hiddenCategoryId; + private final String currencyCode; public PromoCodeDiscount(@Column("id")int id, @Column("promo_code") String promoCode, @@ -75,7 +77,8 @@ public PromoCodeDiscount(@Column("id")int id, @Column("description") String description, @Column("email_reference") String emailReference, @Column("code_type") CodeType codeType, - @Column("hidden_category_id") Integer hiddenCategoryId) { + @Column("hidden_category_id") Integer hiddenCategoryId, + @Column("currency_code") String currencyCode) { this.id = id; this.promoCode = promoCode; @@ -96,6 +99,7 @@ public PromoCodeDiscount(@Column("id")int id, this.emailReference = emailReference; this.codeType = codeType; this.hiddenCategoryId = hiddenCategoryId; + this.currencyCode = currencyCode; } public boolean isCurrentlyValid(ZoneId eventZoneId, ZonedDateTime now) { @@ -125,10 +129,18 @@ public boolean isDynamic() { return codeType == CodeType.DYNAMIC; } + public boolean hasCurrencyCode() { + return StringUtils.length(currencyCode) == 3; + } + public static String format(PromoCodeDiscount discount, String eventCurrencyCode) { if(discount.getDiscountType() == DiscountType.PERCENTAGE) { return Integer.toString(discount.getDiscountAmount()); } return MonetaryUtil.formatCents(discount.getDiscountAmount(), eventCurrencyCode); } + + public static boolean supportsCurrencyCode(CodeType codeType, DiscountType discountType) { + return codeType == CodeType.DISCOUNT && discountType != DiscountType.PERCENTAGE; + } } diff --git a/src/main/java/alfio/model/PromoCodeUsageResult.java b/src/main/java/alfio/model/PromoCodeUsageResult.java new file mode 100644 index 0000000000..db052d5b01 --- /dev/null +++ b/src/main/java/alfio/model/PromoCodeUsageResult.java @@ -0,0 +1,59 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model; + +import alfio.model.support.EventBasicInfo; +import alfio.model.support.ReservationInfo; +import alfio.util.Json; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class PromoCodeUsageResult { + + private final String promoCode; + private final EventBasicInfo event; + private final List reservations; + + public PromoCodeUsageResult(@Column("promo_code") String promoCode, + @Column("event_short_name") String eventShortName, + @Column("event_display_name") String eventDisplayName, + @Column("reservations") String reservationsJson) { + this.promoCode = promoCode; + this.event = new EventBasicInfo(eventShortName, eventDisplayName); + List parsed = Json.fromJson(reservationsJson, new TypeReference<>() {}); + this.reservations = parsed.stream() + .sorted(Comparator.comparing(ReservationInfo::getConfirmationTimestamp)) + .collect(Collectors.toList()); + } + + public String getPromoCode() { + return promoCode; + } + + public EventBasicInfo getEvent() { + return event; + } + + public List getReservations() { + return reservations; + } + +} diff --git a/src/main/java/alfio/model/PurchaseContext.java b/src/main/java/alfio/model/PurchaseContext.java index cb818c17a8..7e6d6b4cc9 100644 --- a/src/main/java/alfio/model/PurchaseContext.java +++ b/src/main/java/alfio/model/PurchaseContext.java @@ -67,11 +67,11 @@ enum PurchaseContextType { } public static PurchaseContextType from(String purchaseContextType) { - switch (purchaseContextType) { - case "subscription": return subscription; - case "event": return event; - default: throw new IllegalStateException("Purchase type not supported:" + purchaseContextType); - } + return switch (purchaseContextType) { + case "subscription" -> subscription; + case "event" -> event; + default -> throw new IllegalStateException("Purchase type not supported:" + purchaseContextType); + }; } public String getUrlComponent() { diff --git a/src/main/java/alfio/model/ReservationMetadata.java b/src/main/java/alfio/model/ReservationMetadata.java new file mode 100644 index 0000000000..402faf3787 --- /dev/null +++ b/src/main/java/alfio/model/ReservationMetadata.java @@ -0,0 +1,70 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ReservationMetadata { + + private final boolean hideContactData; + private final boolean readyForConfirmation; + private final boolean finalized; + private final boolean hideConfirmationButtons; + private final boolean lockEmailEdit; + + @JsonCreator + public ReservationMetadata(@JsonProperty("hideContactData") Boolean hideContactData, + @JsonProperty("readyForConfirmation") Boolean readyForConfirmation, + @JsonProperty("finalized") Boolean finalized, + @JsonProperty("hideConfirmationButtons") Boolean hideConfirmationButtons, + @JsonProperty("lockEmailEdit") Boolean lockEmailEdit) { + this.hideContactData = Boolean.TRUE.equals(hideContactData); + this.readyForConfirmation = Boolean.TRUE.equals(readyForConfirmation); + this.finalized = Boolean.TRUE.equals(finalized); + this.hideConfirmationButtons = Boolean.TRUE.equals(hideConfirmationButtons); + this.lockEmailEdit = Boolean.TRUE.equals(lockEmailEdit); + } + + public boolean isHideContactData() { + return hideContactData; + } + + public boolean isFinalized() { + return finalized; + } + + public boolean isReadyForConfirmation() { + return readyForConfirmation; + } + + public boolean isHideConfirmationButtons() { + return hideConfirmationButtons; + } + + public boolean isLockEmailEdit() { + return lockEmailEdit; + } + + public ReservationMetadata withFinalized(boolean newValue) { + return new ReservationMetadata(hideContactData, readyForConfirmation, newValue, hideConfirmationButtons, lockEmailEdit); + } + + public ReservationMetadata withReadyForConfirmation(boolean newValue) { + return new ReservationMetadata(hideContactData, newValue, finalized, hideConfirmationButtons, lockEmailEdit); + } +} diff --git a/src/main/java/alfio/model/ReservationPaymentDetail.java b/src/main/java/alfio/model/ReservationPaymentDetail.java new file mode 100644 index 0000000000..770e8e616d --- /dev/null +++ b/src/main/java/alfio/model/ReservationPaymentDetail.java @@ -0,0 +1,97 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model; + +import alfio.util.MonetaryUtil; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; + +import java.time.ZonedDateTime; + +public class ReservationPaymentDetail { + private final String id; + private final String firstName; + private final String lastName; + private final String email; + private final String paymentMethod; + private final String paidAmount; + private final String currencyCode; + private final String transactionTimestamp; + private final String transactionNotes; + private final String invoiceNumber; + + public ReservationPaymentDetail(@Column("tr_id") String id, + @Column("tr_first_name") String firstName, + @Column("tr_last_name") String lastName, + @Column("tr_email_address") String email, + @Column("tr_payment_method") String paymentMethod, + @Column("bt_price_cts") Integer paidAmount, + @Column("bt_currency") String currencyCode, + @Column("bt_t_timestamp") ZonedDateTime transactionTimestamp, + @Column("bt_notes") String transactionNotes, + @Column("tr_invoice_number") String invoiceNumber) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.paymentMethod = paymentMethod; + this.paidAmount = MonetaryUtil.formatCents(paidAmount, currencyCode); + this.currencyCode = currencyCode; + this.transactionTimestamp = transactionTimestamp.toString(); + this.transactionNotes = transactionNotes; + this.invoiceNumber = invoiceNumber; + } + + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public String getPaymentMethod() { + return paymentMethod; + } + + public String getPaidAmount() { + return paidAmount; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public String getTransactionTimestamp() { + return transactionTimestamp; + } + + public String getTransactionNotes() { + return transactionNotes; + } + + public String getInvoiceNumber() { + return invoiceNumber; + } +} diff --git a/src/main/java/alfio/model/ReservationWithPurchaseContext.java b/src/main/java/alfio/model/ReservationWithPurchaseContext.java index a471719fb6..4f84ed1a53 100644 --- a/src/main/java/alfio/model/ReservationWithPurchaseContext.java +++ b/src/main/java/alfio/model/ReservationWithPurchaseContext.java @@ -20,8 +20,9 @@ import alfio.model.transaction.PaymentProxy; import alfio.util.Json; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; -import lombok.AllArgsConstructor; import lombok.Getter; import java.math.BigDecimal; @@ -123,12 +124,23 @@ public BigDecimal getAppliedDiscount() { return centsToUnit(discountCts, currencyCode); } - @AllArgsConstructor + @Getter public static class PurchaseContextItem { private final String id; private final String firstName; private final String lastName; private final Map type; + + @JsonCreator + public PurchaseContextItem(@JsonProperty("id") String id, + @JsonProperty("firstName") String firstName, + @JsonProperty("lastName") String lastName, + @JsonProperty("type") Map type) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.type = type; + } } } diff --git a/src/main/java/alfio/model/ReservationsByEvent.java b/src/main/java/alfio/model/ReservationsByEvent.java new file mode 100644 index 0000000000..30380d1e36 --- /dev/null +++ b/src/main/java/alfio/model/ReservationsByEvent.java @@ -0,0 +1,58 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model; + +import alfio.model.support.ReservationInfo; +import alfio.util.Json; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.List; + +public class ReservationsByEvent { + + private final int eventId; + private final String eventShortName; + private final String displayName; + private final List reservations; + + public ReservationsByEvent(@Column("event_id") int eventId, + @Column("event_short_name") String eventShortName, + @Column("event_display_name") String displayName, + @Column("reservations") String reservations) { + this.eventId = eventId; + this.eventShortName = eventShortName; + this.displayName = displayName; + this.reservations = Json.fromJson(reservations, new TypeReference<>() {}); + } + + public int getEventId() { + return eventId; + } + + public String getEventShortName() { + return eventShortName; + } + + public String getDisplayName() { + return displayName; + } + + public List getReservations() { + return reservations; + } +} diff --git a/src/main/java/alfio/model/RestrictedValueStats.java b/src/main/java/alfio/model/RestrictedValueStats.java index 2b674bd41d..ad4457169b 100644 --- a/src/main/java/alfio/model/RestrictedValueStats.java +++ b/src/main/java/alfio/model/RestrictedValueStats.java @@ -18,7 +18,6 @@ import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; import lombok.Data; -import lombok.Getter; @Data public class RestrictedValueStats { @@ -26,14 +25,7 @@ public class RestrictedValueStats { private final int count; private final int percentage; - @Getter - public static class RestrictedValueCount { - private final String name; - private final Integer count; - public RestrictedValueCount(@Column("name") String name, @Column("count") Integer count) { - this.name = name; - this.count = count; - } + public record RestrictedValueCount(@Column("name") String name, @Column("count") Integer count) { } } diff --git a/src/main/java/alfio/model/SponsorScan.java b/src/main/java/alfio/model/SponsorScan.java index 38426a3e49..1e069fd335 100644 --- a/src/main/java/alfio/model/SponsorScan.java +++ b/src/main/java/alfio/model/SponsorScan.java @@ -34,6 +34,7 @@ public enum LeadStatus { private final int ticketId; private final String notes; private final LeadStatus leadStatus; + private final String operator; public SponsorScan(@Column("user_id") int userId, @@ -41,12 +42,14 @@ public SponsorScan(@Column("user_id") int userId, @Column("event_id") int eventId, @Column("ticket_id") int ticketId, @Column("notes") String notes, - @Column("lead_status") LeadStatus leadStatus) { + @Column("lead_status") LeadStatus leadStatus, + @Column("operator") String operator) { this.userId = userId; this.timestamp = timestamp; this.eventId = eventId; this.ticketId = ticketId; this.notes = notes; this.leadStatus = leadStatus; + this.operator = operator; } } diff --git a/src/main/java/alfio/model/SummaryRow.java b/src/main/java/alfio/model/SummaryRow.java index d28d0c1107..49ff0f5690 100644 --- a/src/main/java/alfio/model/SummaryRow.java +++ b/src/main/java/alfio/model/SummaryRow.java @@ -16,26 +16,22 @@ */ package alfio.model; -import lombok.Data; - -@Data -public class SummaryRow { - private final String name; - private final String price; - private final String priceBeforeVat; - private final int amount; - private final String subTotal; - private final String subTotalBeforeVat; - private final int originalSubTotal; - private final SummaryType type; - private final String taxPercentage; - +public record SummaryRow(String name, + String price, + String priceBeforeVat, + int amount, + String subTotal, + String subTotalBeforeVat, + int originalSubTotal, + SummaryType type, + String taxPercentage, + PriceContainer.VatStatus vatStatus) { public enum SummaryType { TICKET, SUBSCRIPTION, PROMOTION_CODE, DYNAMIC_DISCOUNT, ADDITIONAL_SERVICE, APPLIED_SUBSCRIPTION, TAX_DETAIL } public String getDescriptionForPayment() { - if(name != null) { + if (name != null) { return amount + " x " + name; } return ""; diff --git a/src/main/java/alfio/model/Ticket.java b/src/main/java/alfio/model/Ticket.java index e02d9576da..caf9d7377a 100644 --- a/src/main/java/alfio/model/Ticket.java +++ b/src/main/java/alfio/model/Ticket.java @@ -18,6 +18,7 @@ import alfio.model.support.Array; import alfio.util.MonetaryUtil; +import alfio.util.checkin.NameNormalizer; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -126,12 +127,12 @@ public boolean getLockedAssignment() { * @param eventKey * @return */ - public String ticketCode(String eventKey) { - return uuid + '/' + hmacTicketInfo(eventKey); + public String ticketCode(String eventKey, boolean caseInsensitive) { + return uuid + '/' + hmacTicketInfo(eventKey, caseInsensitive); } - public String hmacTicketInfo(String eventKey) { - return hmacSHA256Base64(eventKey, StringUtils.join(new String[]{ticketsReservationId , uuid, getFullName(), email}, '/')); + public String hmacTicketInfo(String eventKey, boolean caseInsensitive) { + return generateHmacTicketInfo(eventKey, caseInsensitive, getFullName(), email, ticketsReservationId, uuid); } public boolean hasBeenSold() { @@ -143,6 +144,16 @@ public boolean isCheckedIn() { return status == TicketStatus.CHECKED_IN; } + static String generateHmacTicketInfo(String eventKey, boolean caseInsensitive, String fullName, String email, String ticketsReservationId, String uuid) { + var attendeeName = fullName; + var attendeeEmail = email; + if (caseInsensitive) { + attendeeName = NameNormalizer.normalize(attendeeName); + attendeeEmail = email.toLowerCase(Locale.ROOT); + } + return hmacSHA256Base64(eventKey, StringUtils.join(new String[]{ticketsReservationId , uuid, attendeeName, attendeeEmail}, '/')); + } + public static String hmacSHA256Base64(String key, String code) { return Base64.getEncoder().encodeToString(new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(code)); } @@ -158,4 +169,31 @@ public String getFormattedFinalPrice() { public String getFormattedNetPrice() { return MonetaryUtil.formatCents(finalPriceCts - vatCts, currencyCode); } + + public Ticket withVatStatus(PriceContainer.VatStatus newVatStatus) { + return new Ticket( + id, + uuid, + creation, + categoryId, + status.name(), + eventId, + ticketsReservationId, + fullName, + firstName, + lastName, + email, + lockedAssignment, + userLanguage, + srcPriceCts, + finalPriceCts, + vatCts, + discountCts, + extReference, + currencyCode, + tags, + subscriptionId, + newVatStatus + ); + } } diff --git a/src/main/java/alfio/model/TicketCategoryStatisticView.java b/src/main/java/alfio/model/TicketCategoryStatisticView.java index f398818da0..0b8d60b6ea 100644 --- a/src/main/java/alfio/model/TicketCategoryStatisticView.java +++ b/src/main/java/alfio/model/TicketCategoryStatisticView.java @@ -16,9 +16,16 @@ */ package alfio.model; +import alfio.model.system.Configuration; +import alfio.util.Json; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.core.type.TypeReference; import lombok.Getter; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Objects; + @Getter public class TicketCategoryStatisticView { @@ -36,6 +43,7 @@ public class TicketCategoryStatisticView { private final int stuckCount; private final boolean containsOrphanTickets; private final boolean containsStuckTickets; + private final List configuration; public TicketCategoryStatisticView(@Column("ticket_category_id") int id, @Column("max_tickets") int maxTickets, @@ -49,7 +57,8 @@ public TicketCategoryStatisticView(@Column("ticket_category_id") int id, @Column("released_count") int releasedCount, @Column("stuck_count") int stuckCount, @Column("is_containing_orphan_tickets") boolean containsOrphanTickets, - @Column("is_containing_stuck_tickets") boolean containsStuckTickets) { + @Column("is_containing_stuck_tickets") boolean containsStuckTickets, + @Column("category_configuration") String configurationJson) { this.id = id; this.maxTickets = maxTickets; this.bounded = bounded; @@ -63,9 +72,10 @@ public TicketCategoryStatisticView(@Column("ticket_category_id") int id, this.containsOrphanTickets = containsOrphanTickets; this.containsStuckTickets = containsStuckTickets; this.releasedTicketsCount = releasedCount; + this.configuration = Json.fromJson(Objects.requireNonNullElse(configurationJson, "[]"), new TypeReference<>() {}); } public static TicketCategoryStatisticView empty(int ticketCategoryId, int eventId) { - return new TicketCategoryStatisticView(ticketCategoryId, 0, false, false, eventId, 0, 0, 0, 0, 0, 0, false, false); + return new TicketCategoryStatisticView(ticketCategoryId, 0, false, false, eventId, 0, 0, 0, 0, 0, 0, false, false, null); } } diff --git a/src/main/java/alfio/model/TicketCategoryWithAdditionalInfo.java b/src/main/java/alfio/model/TicketCategoryWithAdditionalInfo.java index 2aa26216d0..549308077b 100644 --- a/src/main/java/alfio/model/TicketCategoryWithAdditionalInfo.java +++ b/src/main/java/alfio/model/TicketCategoryWithAdditionalInfo.java @@ -19,10 +19,10 @@ import alfio.model.metadata.AlfioMetadata; import alfio.model.modification.StatisticsContainer; import alfio.model.modification.TicketWithStatistic; +import alfio.model.system.Configuration; import alfio.util.ClockProvider; import alfio.util.MonetaryUtil; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.experimental.Delegate; @@ -33,7 +33,6 @@ import java.util.Map; import java.util.Optional; -@AllArgsConstructor @Getter public class TicketCategoryWithAdditionalInfo implements StatisticsContainer, PriceContainer { @@ -57,6 +56,20 @@ public class TicketCategoryWithAdditionalInfo implements StatisticsContainer, Pr @Deprecated private final List tickets = Collections.emptyList(); + public TicketCategoryWithAdditionalInfo(Event event, + TicketCategory ticketCategory, + TicketCategoryStatisticView ticketCategoryStatisticView, + Map description, + List tokenStatus, + AlfioMetadata metadata) { + this.event = event; + this.ticketCategory = ticketCategory; + this.ticketCategoryStatisticView = ticketCategoryStatisticView; + this.description = description; + this.tokenStatus = tokenStatus; + this.metadata = metadata; + } + @JsonIgnore public Event getEvent() { return event; @@ -170,4 +183,8 @@ public Optional getOptionalVatPercentage() { public VatStatus getVatStatus() { return event.getVatStatus(); } + + public List getConfiguration() { + return ticketCategoryStatisticView.getConfiguration(); + } } diff --git a/src/main/java/alfio/model/TicketFieldConfiguration.java b/src/main/java/alfio/model/TicketFieldConfiguration.java index d249d11fa6..869a3f38f2 100644 --- a/src/main/java/alfio/model/TicketFieldConfiguration.java +++ b/src/main/java/alfio/model/TicketFieldConfiguration.java @@ -97,6 +97,10 @@ public boolean isSelectField() { return "select".equals(type); } + public boolean isCheckboxField() { + return "checkbox".equals(type); + } + public int getCount() { if ("checkbox".equals(type) && this.restrictedValues != null) { return Math.max(this.restrictedValues.size(), 1); diff --git a/src/main/java/alfio/model/TicketFieldConfigurationDescriptionAndValue.java b/src/main/java/alfio/model/TicketFieldConfigurationDescriptionAndValue.java index 6e199d39c8..2678f17d79 100644 --- a/src/main/java/alfio/model/TicketFieldConfigurationDescriptionAndValue.java +++ b/src/main/java/alfio/model/TicketFieldConfigurationDescriptionAndValue.java @@ -18,21 +18,20 @@ import alfio.util.Json; import com.fasterxml.jackson.core.type.TypeReference; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Triple; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; -@AllArgsConstructor public class TicketFieldConfigurationDescriptionAndValue { @Delegate @@ -42,6 +41,24 @@ public class TicketFieldConfigurationDescriptionAndValue { private final int count; private final String value; + private static final List TEXT_FIELD_TYPES = List.of( + "text", + "tel", + "textarea", + "vat:eu" + ); + private static final Pattern CHECKBOX_VALUES_PATTERN = Pattern.compile("\"(.*?)\",?"); + + public TicketFieldConfigurationDescriptionAndValue(TicketFieldConfiguration ticketFieldConfiguration, + TicketFieldDescription ticketFieldDescription, + int count, + String value) { + this.ticketFieldConfiguration = ticketFieldConfiguration; + this.ticketFieldDescription = ticketFieldDescription; + this.count = count; + this.value = value; + } + public String getTranslatedValue() { if(StringUtils.isBlank(value)) { return value; @@ -71,18 +88,38 @@ public List getFields() { } + private boolean isText() { + return TEXT_FIELD_TYPES.contains(getType()); + } + public String getValueDescription() { - if(isSelectField()) { - return getTranslatedRestrictedValue().stream() - .filter(t -> StringUtils.equals(t.getLeft(), value)) - .map(Triple::getMiddle) - .findFirst() - .orElse(""); - } else { + if(isText()) { return value; + } else if(isCheckboxField()) { + var matches = new ArrayList(); + var matcher = CHECKBOX_VALUES_PATTERN.matcher(value); + while(matcher.find()) { + matches.add(matcher.group(1)); + } + var restrictedValues = getTranslatedRestrictedValue(); + return matches.stream() + .map(v -> findValueDescription(restrictedValues, v)) + .filter(StringUtils::isNotBlank) + .collect(Collectors.joining(", ")); + } else { + return findValueDescription(getTranslatedRestrictedValue(), value); } } + private String findValueDescription(List> translateRestrictedValues, + String value) { + return translateRestrictedValues.stream() + .filter(t -> StringUtils.equals(t.getLeft(), value)) + .map(Triple::getMiddle) + .findFirst() + .orElse(""); + } + public String getValue() { return value; } @@ -101,13 +138,20 @@ private static boolean isFieldValueEnabled(TicketFieldConfiguration ticketFieldC || !ticketFieldConfiguration.getDisabledValues().contains(value); } - @RequiredArgsConstructor + @Getter public static class TicketFieldValue { private final int fieldIndex; private final int fieldCounter; private final String fieldValue; private final Boolean editable; + + public TicketFieldValue(int fieldIndex, int fieldCounter, String fieldValue, Boolean editable) { + this.fieldIndex = fieldIndex; + this.fieldCounter = fieldCounter; + this.fieldValue = fieldValue; + this.editable = editable; + } } } diff --git a/src/main/java/alfio/model/TicketInfo.java b/src/main/java/alfio/model/TicketInfo.java index 29ee8f536a..0209b5c51f 100644 --- a/src/main/java/alfio/model/TicketInfo.java +++ b/src/main/java/alfio/model/TicketInfo.java @@ -23,15 +23,21 @@ public class TicketInfo { private final int ticketId; + private final String ticketUuid; private final int ticketCategoryId; private final boolean ticketCategoryBounded; + private final PriceContainer.VatStatus taxPolicy; public TicketInfo(@Column("t_id") int id, + @Column("t_uuid") String ticketUuid, @Column("tc_id") int tcId, - @Column("tc_bounded") boolean bounded) { + @Column("tc_bounded") boolean bounded, + @Column("t_vat_status") PriceContainer.VatStatus taxPolicy) { this.ticketId = id; + this.ticketUuid = ticketUuid; this.ticketCategoryId = tcId; this.ticketCategoryBounded = bounded; + this.taxPolicy = taxPolicy; } } diff --git a/src/main/java/alfio/model/TicketReservation.java b/src/main/java/alfio/model/TicketReservation.java index ff98ba0e22..6b34d31e31 100644 --- a/src/main/java/alfio/model/TicketReservation.java +++ b/src/main/java/alfio/model/TicketReservation.java @@ -21,7 +21,6 @@ import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; -import lombok.With; import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; @@ -39,6 +38,14 @@ public enum TicketReservationStatus { WAITING_EXTERNAL_CONFIRMATION, OFFLINE_PAYMENT, DEFERRED_OFFLINE_PAYMENT, + /** + * Reservation is in the process of being finalized + */ + FINALIZING, + /** + * Special finalization status for OFFLINE payment + */ + OFFLINE_FINALIZING, COMPLETE, STUCK, CANCELLED, @@ -64,7 +71,6 @@ public enum TicketReservationStatus { private final String invoiceNumber; @JsonIgnore private final String invoiceModel; - @With private final PriceContainer.VatStatus vatStatus; private final String vatNr; private final String vatCountryCode; @@ -204,6 +210,44 @@ public String getPaidAmount() { return null; } + public TicketReservation withVatStatus(PriceContainer.VatStatus vatStatus) { + if (this.vatStatus == vatStatus) { + return this; + } + return new TicketReservation(this.id, + this.validity, + this.status, + this.fullName, + this.firstName, + this.lastName, + this.email, + this.billingAddress, + this.confirmationTimestamp, + this.latestReminder, + this.paymentMethod, + this.reminderSent, + this.promoCodeDiscountId, + this.automatic, + this.userLanguage, + this.directAssignmentRequested, + this.invoiceNumber, + this.invoiceModel, + vatStatus, + this.vatNr, + this.vatCountryCode, + this.invoiceRequested, + this.usedVatPercent, + this.vatIncluded, + this.creationTimestamp, + this.customerReference, + this.registrationTimestamp, + this.srcPriceCts, + this.finalPriceCts, + this.vatCts, + this.discountCts, + this.currencyCode); + } + @Override public Optional getOptionalVatPercentage() { return Optional.ofNullable(usedVatPercent); diff --git a/src/main/java/alfio/model/TicketReservationInvoicingAdditionalInfo.java b/src/main/java/alfio/model/TicketReservationInvoicingAdditionalInfo.java index 7e9e5aa246..13731006ce 100644 --- a/src/main/java/alfio/model/TicketReservationInvoicingAdditionalInfo.java +++ b/src/main/java/alfio/model/TicketReservationInvoicingAdditionalInfo.java @@ -16,15 +16,20 @@ */ package alfio.model; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @Getter -@AllArgsConstructor public class TicketReservationInvoicingAdditionalInfo { private final ItalianEInvoicing italianEInvoicing; + @JsonCreator + public TicketReservationInvoicingAdditionalInfo(@JsonProperty("italianEInvoicing") ItalianEInvoicing italianEInvoicing) { + this.italianEInvoicing = italianEInvoicing; + } + public boolean isEmpty() { return italianEInvoicing == null || italianEInvoicing.isEmpty(); } @@ -37,7 +42,6 @@ public boolean getEmpty() { // https://github.com/alfio-event/alf.io/issues/573 // @Getter - @AllArgsConstructor public static class ItalianEInvoicing { public enum ReferenceType { @@ -52,6 +56,19 @@ public enum ReferenceType { private final String pec; private final boolean splitPayment; + @JsonCreator + public ItalianEInvoicing(@JsonProperty("fiscalCode") String fiscalCode, + @JsonProperty("referenceType") ReferenceType referenceType, + @JsonProperty("addresseeCode") String addresseeCode, + @JsonProperty("pec") String pec, + @JsonProperty("splitPayment") boolean splitPayment) { + this.fiscalCode = fiscalCode; + this.referenceType = referenceType; + this.addresseeCode = addresseeCode; + this.pec = pec; + this.splitPayment = splitPayment; + } + public String getReferenceTypeAsString() { return referenceType == null ? "" : referenceType.toString(); } diff --git a/src/main/java/alfio/model/TicketWithCategory.java b/src/main/java/alfio/model/TicketWithCategory.java index 2fb97e48da..a501c936e4 100644 --- a/src/main/java/alfio/model/TicketWithCategory.java +++ b/src/main/java/alfio/model/TicketWithCategory.java @@ -16,16 +16,19 @@ */ package alfio.model; -import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; -@RequiredArgsConstructor public class TicketWithCategory implements TicketInfoContainer { @Delegate private final Ticket ticket; private final TicketCategory category; + public TicketWithCategory(Ticket ticket, TicketCategory category) { + this.ticket = ticket; + this.category = category; + } + public String getCategoryName() { return category != null ? category.getName() : null; } diff --git a/src/main/java/alfio/model/TotalPrice.java b/src/main/java/alfio/model/TotalPrice.java index 399ccc5aa4..a4c3125185 100644 --- a/src/main/java/alfio/model/TotalPrice.java +++ b/src/main/java/alfio/model/TotalPrice.java @@ -16,30 +16,13 @@ */ package alfio.model; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -@Getter -public class TotalPrice { - private final int priceWithVAT; - private final int VAT; - private final int discount; - private final int discountAppliedCount; - private final String currencyCode; - - @JsonCreator - public TotalPrice(@JsonProperty("priceWithVAT") int priceWithVAT, - @JsonProperty("vat") int VAT, - @JsonProperty("discount") int discount, - @JsonProperty("discountAppliedCount") int discountAppliedCount, - @JsonProperty("currencyCode") String currencyCode) { - this.priceWithVAT = priceWithVAT; - this.VAT = VAT; - this.discount = discount; - this.discountAppliedCount = discountAppliedCount; - this.currencyCode = currencyCode; - } +public record TotalPrice(@JsonProperty("priceWithVAT") int priceWithVAT, + @JsonProperty("vat") int VAT, + @JsonProperty("discount") int discount, + @JsonProperty("discountAppliedCount") int discountAppliedCount, + @JsonProperty("currencyCode") String currencyCode) { public boolean requiresPayment() { return this.priceWithVAT > 0; diff --git a/src/main/java/alfio/model/TransactionAndPaymentInfo.java b/src/main/java/alfio/model/TransactionAndPaymentInfo.java index 086e34d857..3534d8dfb1 100644 --- a/src/main/java/alfio/model/TransactionAndPaymentInfo.java +++ b/src/main/java/alfio/model/TransactionAndPaymentInfo.java @@ -19,15 +19,10 @@ import alfio.model.transaction.PaymentProxy; import alfio.model.transaction.Transaction; -import lombok.AllArgsConstructor; -import lombok.Getter; -@Getter -@AllArgsConstructor -public class TransactionAndPaymentInfo { - private final PaymentProxy paymentMethod; - private final Transaction transaction; - private final PaymentInformation paymentInformation; +public record TransactionAndPaymentInfo(PaymentProxy paymentMethod, + Transaction transaction, + PaymentInformation paymentInformation) { public boolean isSupportRefund() { return paymentMethod != null && paymentMethod.isSupportRefund(); diff --git a/src/main/java/alfio/model/WaitingQueueSubscription.java b/src/main/java/alfio/model/WaitingQueueSubscription.java index 0336e8d7ec..f208636391 100644 --- a/src/main/java/alfio/model/WaitingQueueSubscription.java +++ b/src/main/java/alfio/model/WaitingQueueSubscription.java @@ -19,14 +19,13 @@ import alfio.util.LocaleUtil; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; import lombok.Getter; -import lombok.ToString; +import org.apache.commons.lang3.builder.ToStringBuilder; import java.time.ZonedDateTime; import java.util.Locale; import java.util.Optional; @Getter -@ToString public class WaitingQueueSubscription { public enum Status { @@ -83,4 +82,22 @@ public Locale getLocale() { public boolean isPreSales() { return Optional.ofNullable(subscriptionType).map(s -> s == Type.PRE_SALES).orElse(false); } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("id", id) + .append("creation", creation) + .append("eventId", eventId) + .append("status", status) + .append("fullName", fullName) + .append("firstName", firstName) + .append("lastName", lastName) + .append("emailAddress", emailAddress) + .append("reservationId", reservationId) + .append("userLanguage", userLanguage) + .append("selectedCategoryId", selectedCategoryId) + .append("subscriptionType", subscriptionType) + .toString(); + } } diff --git a/src/main/java/alfio/model/api/v1/admin/AttendeesByCategory.java b/src/main/java/alfio/model/api/v1/admin/AttendeesByCategory.java new file mode 100644 index 0000000000..09bc3ed61f --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/AttendeesByCategory.java @@ -0,0 +1,68 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import alfio.model.modification.AttendeeData; +import alfio.model.modification.ReservationRequest; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +public class AttendeesByCategory implements ReservationRequest { + + private final Integer ticketCategoryId; + private final Integer quantity; + private final List attendees; + // only for backwards compatibility + private final List> metadata; + + @JsonCreator + public AttendeesByCategory(@JsonProperty("ticketCategoryId") Integer ticketCategoryId, + @JsonProperty("quantity") Integer quantity, + @JsonProperty("attendees") List attendees, + @JsonProperty("metadata") List> metadata) { + this.ticketCategoryId = ticketCategoryId; + this.quantity = quantity; + this.attendees = attendees; + this.metadata = metadata; + } + + @Override + public Integer getTicketCategoryId() { + return ticketCategoryId; + } + + @Override + public Integer getQuantity() { + return quantity; + } + + @Override + public List getAttendees() { + if (attendees != null && !attendees.isEmpty()) { + return attendees; + } + return ReservationRequest.metadataToAttendeesList(getQuantity(), metadata); + } + + @Override + public List> getMetadata() { + return metadata; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java b/src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java new file mode 100644 index 0000000000..85100e34df --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/CheckInLogEntry.java @@ -0,0 +1,52 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import alfio.model.audit.ScanAudit; +import alfio.model.modification.AttendeeData; +import alfio.model.support.JSONData; +import alfio.util.Json; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.List; + +public class CheckInLogEntry { + private final String ticketId; + private final AttendeeData attendeeData; + private final List audit; + + public CheckInLogEntry(@Column("t_uuid") String ticketId, + @Column("attendee_data") @JSONData AttendeeData attendeeData, + @Column("scans") String scansAsString) { + this.ticketId = ticketId; + this.attendeeData = attendeeData; + this.audit = Json.fromJson(scansAsString, new TypeReference<>() {}); + } + + public String getTicketId() { + return ticketId; + } + + public AttendeeData getAttendeeData() { + return attendeeData; + } + + public List getAudit() { + return audit; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java b/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java index 205ab18ae8..017aa62c3c 100644 --- a/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java +++ b/src/main/java/alfio/model/api/v1/admin/EventCreationRequest.java @@ -25,7 +25,8 @@ import alfio.model.modification.support.LocationDescriptor; import alfio.model.transaction.PaymentProxy; import alfio.model.user.Organization; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -42,28 +43,60 @@ import static org.apache.commons.collections.CollectionUtils.isEmpty; @Getter -@AllArgsConstructor public class EventCreationRequest{ - private String title; - private String slug; - private List description; - private Event.EventFormat format; - private LocationRequest location; - private String timezone; - private LocalDateTime startDate; - private LocalDateTime endDate; - private String websiteUrl; - private String termsAndConditionsUrl; - private String privacyPolicyUrl; - private String imageUrl; - private TicketRequest tickets; - private List extensionSettings; - private List additionalInfo; + private final String title; + private final String slug; + private final List description; + private final Event.EventFormat format; + private final LocationRequest location; + private final String timezone; + private final LocalDateTime startDate; + private final LocalDateTime endDate; + private final String websiteUrl; + private final String termsAndConditionsUrl; + private final String privacyPolicyUrl; + private final String imageUrl; + private final TicketRequest tickets; + private final List extensionSettings; + private final List additionalInfo; + + @JsonCreator + public EventCreationRequest(@JsonProperty("title") String title, + @JsonProperty("slug") String slug, + @JsonProperty("description") List description, + @JsonProperty("format") Event.EventFormat format, + @JsonProperty("location") LocationRequest location, + @JsonProperty("timezone") String timezone, + @JsonProperty("startDate") LocalDateTime startDate, + @JsonProperty("endDate") LocalDateTime endDate, + @JsonProperty("websiteUrl") String websiteUrl, + @JsonProperty("termsAndConditionsUrl") String termsAndConditionsUrl, + @JsonProperty("privacyPolicyUrl") String privacyPolicyUrl, + @JsonProperty("imageUrl") String imageUrl, + @JsonProperty("tickets") TicketRequest tickets, + @JsonProperty("extensionSettings") List extensionSettings, + @JsonProperty("additionalInfo") List additionalInfo) { + this.title = title; + this.slug = slug; + this.description = description; + this.format = format; + this.location = location; + this.timezone = timezone; + this.startDate = startDate; + this.endDate = endDate; + this.websiteUrl = websiteUrl; + this.termsAndConditionsUrl = termsAndConditionsUrl; + this.privacyPolicyUrl = privacyPolicyUrl; + this.imageUrl = imageUrl; + this.tickets = tickets; + this.extensionSettings = extensionSettings; + this.additionalInfo = additionalInfo; + } public EventModification toEventModification(Organization organization, UnaryOperator slugGenerator, String imageRef) { - String slug = this.slug; - if(StringUtils.isBlank(slug)) { - slug = slugGenerator.apply(title); + String eventSlug = this.slug; + if(StringUtils.isBlank(eventSlug)) { + eventSlug = slugGenerator.apply(title); } int locales = description.stream() @@ -81,7 +114,7 @@ public EventModification toEventModification(Organization organization, UnaryOpe StringUtils.trimToNull(privacyPolicyUrl), null, imageRef, - slug, + eventSlug, title, organization.getId(), location.getFullAddress(), @@ -91,13 +124,13 @@ public EventModification toEventModification(Organization organization, UnaryOpe description.stream().collect(Collectors.toMap(DescriptionRequest::getLang,DescriptionRequest::getBody)), new DateTimeModification(startDate.toLocalDate(),startDate.toLocalTime()), new DateTimeModification(endDate.toLocalDate(),endDate.toLocalTime()), - tickets.freeOfCharge ? BigDecimal.ZERO : tickets.categories.stream().map(x -> x.price).max(BigDecimal::compareTo).orElse(BigDecimal.ONE).max(BigDecimal.ONE), + Boolean.TRUE.equals(tickets.freeOfCharge) ? BigDecimal.ZERO : tickets.categories.stream().map(x -> x.price).max(BigDecimal::compareTo).orElse(BigDecimal.ONE).max(BigDecimal.ONE), tickets.currency, tickets.max, tickets.taxPercentage, tickets.taxIncludedInPrice, tickets.paymentMethods, - tickets.categories.stream().map(CategoryRequest::toTicketCategoryModification).collect(Collectors.toList()), + getTicketCategoryModificationList(), tickets.freeOfCharge, new LocationDescriptor(timezone, location.getCoordinate().getLatitude(), location.getCoordinate().getLongitude(), null), locales, @@ -108,6 +141,14 @@ public EventModification toEventModification(Organization organization, UnaryOpe ); } + private List getTicketCategoryModificationList() { + var result = new ArrayList(); + for (int c = 0; c < tickets.categories.size(); c++) { + result.add(tickets.categories.get(c).toNewTicketCategoryModification(c + 1 )); + } + return List.copyOf(result); + } + private static T first(T value,T other) { return Optional.ofNullable(value).orElse(other); } @@ -150,7 +191,7 @@ public EventModification toEventModificationUpdate(EventWithAdditionalInfo origi tickets != null ? first(tickets.taxPercentage,original.getVat()) : original.getVat(), tickets != null ? first(tickets.taxIncludedInPrice,original.isVatIncluded()) : original.isVatIncluded(), tickets != null ? first(tickets.paymentMethods, original.getAllowedPaymentProxies()) : original.getAllowedPaymentProxies(), - tickets != null && tickets.categories != null ? tickets.categories.stream().map(tc -> tc.toTicketCategoryModification(findCategoryId(original, tc))).collect(Collectors.toList()) : null, + tickets != null && tickets.categories != null ? createFromExistingCategories(original) : null, tickets != null ? first(tickets.freeOfCharge,original.isFreeOfCharge()) : original.isFreeOfCharge(), null, locales, @@ -161,69 +202,145 @@ public EventModification toEventModificationUpdate(EventWithAdditionalInfo origi ); } - private static Integer findCategoryId(EventWithAdditionalInfo event, CategoryRequest categoryRequest) { - return event.getTicketCategories().stream() - .filter(tc -> tc.getName().equals(categoryRequest.getName())) - .map(TicketCategoryWithAdditionalInfo::getId) - .findFirst() - .orElse(null); + private List createFromExistingCategories(EventWithAdditionalInfo event) { + var result = new ArrayList(tickets.categories.size()); + for(int c = 0; c < tickets.categories.size(); c++) { + var categoryRequest = tickets.categories.get(c); + var existing = findExistingCategory(event.getTicketCategories(), categoryRequest.getName(), categoryRequest.getId()); + if (existing.isPresent()) { + var category = existing.get(); + result.add(categoryRequest.toExistingTicketCategoryModification(category.getId(), category.getOrdinal())); + } else { + result.add(categoryRequest.toNewTicketCategoryModification(c + 1)); + } + } + return List.copyOf(result); + } + + public static Optional findExistingCategory(List categories, + String name, + Integer id) { + return categories.stream() + // if specified, ID takes precedence over name + .filter(oc -> id != null ? id == oc.getId() : oc.getName().equals(name)) + .findFirst(); } @Getter - @AllArgsConstructor public static class DescriptionRequest { - private String lang; - private String body; + private final String lang; + private final String body; + + @JsonCreator + public DescriptionRequest(@JsonProperty("lang") String lang, @JsonProperty("body") String body) { + this.lang = lang; + this.body = body; + } } @Getter - @AllArgsConstructor public static class LocationRequest { - private String fullAddress; - private CoordinateRequest coordinate; + private final String fullAddress; + private final CoordinateRequest coordinate; + + @JsonCreator + public LocationRequest(@JsonProperty("fullAddress") String fullAddress, @JsonProperty("coordinate") CoordinateRequest coordinate) { + this.fullAddress = fullAddress; + this.coordinate = coordinate; + } } @Getter - @AllArgsConstructor public static class TicketRequest { - private Boolean freeOfCharge; - private Integer max; - private String currency; - private BigDecimal taxPercentage; - private Boolean taxIncludedInPrice; - private List paymentMethods; - private List categories; - private List promoCodes; + private final Boolean freeOfCharge; + private final Integer max; + private final String currency; + private final BigDecimal taxPercentage; + private final Boolean taxIncludedInPrice; + private final List paymentMethods; + private final List categories; + private final List promoCodes; + + @JsonCreator + public TicketRequest(@JsonProperty("freeOfCharge") Boolean freeOfCharge, + @JsonProperty("max") Integer max, + @JsonProperty("currency") String currency, + @JsonProperty("taxPercentage") BigDecimal taxPercentage, + @JsonProperty("taxIncludedInPrice") Boolean taxIncludedInPrice, + @JsonProperty("paymentMethods") List paymentMethods, + @JsonProperty("categories") List categories, + @JsonProperty("promoCodes") List promoCodes) { + this.freeOfCharge = freeOfCharge; + this.max = max; + this.currency = currency; + this.taxPercentage = taxPercentage; + this.taxIncludedInPrice = taxIncludedInPrice; + this.paymentMethods = paymentMethods; + this.categories = categories; + this.promoCodes = promoCodes; + } } @Getter - @AllArgsConstructor public static class CoordinateRequest { - private String latitude; - private String longitude; + private final String latitude; + private final String longitude; + + @JsonCreator + public CoordinateRequest(@JsonProperty("latitude") String latitude, @JsonProperty("longitude") String longitude) { + this.latitude = latitude; + this.longitude = longitude; + } } @Getter - @AllArgsConstructor public static class CategoryRequest { - private String name; - private List description; - private Integer maxTickets; - private boolean accessRestricted; - private BigDecimal price; - private LocalDateTime startSellingDate; - private LocalDateTime endSellingDate; - private String accessCode; - private CustomTicketValidityRequest customValidity; - private GroupLinkRequest groupLink; - private TicketCategory.TicketAccessType ticketAccessType; - - TicketCategoryModification toTicketCategoryModification() { - return toTicketCategoryModification(null); + private final Integer id; + private final String name; + private final List description; + private final Integer maxTickets; + private final boolean accessRestricted; + private final BigDecimal price; + private final LocalDateTime startSellingDate; + private final LocalDateTime endSellingDate; + private final String accessCode; + private final CustomTicketValidityRequest customValidity; + private final GroupLinkRequest groupLink; + private final TicketCategory.TicketAccessType ticketAccessType; + + @JsonCreator + public CategoryRequest(@JsonProperty("id") Integer id, + @JsonProperty("name") String name, + @JsonProperty("description") List description, + @JsonProperty("maxTickets") Integer maxTickets, + @JsonProperty("accessRestricted") boolean accessRestricted, + @JsonProperty("price") BigDecimal price, + @JsonProperty("startSellingDate") LocalDateTime startSellingDate, + @JsonProperty("endSellingDate") LocalDateTime endSellingDate, + @JsonProperty("accessCode") String accessCode, + @JsonProperty("customValidity") CustomTicketValidityRequest customValidity, + @JsonProperty("groupLink") GroupLinkRequest groupLink, + @JsonProperty("ticketAccessType") TicketCategory.TicketAccessType ticketAccessType) { + this.id = id; + this.name = name; + this.description = description; + this.maxTickets = maxTickets; + this.accessRestricted = accessRestricted; + this.price = price; + this.startSellingDate = startSellingDate; + this.endSellingDate = endSellingDate; + this.accessCode = accessCode; + this.customValidity = customValidity; + this.groupLink = groupLink; + this.ticketAccessType = ticketAccessType; + } + + TicketCategoryModification toNewTicketCategoryModification(int ordinal) { + return toExistingTicketCategoryModification(null, ordinal); } - TicketCategoryModification toTicketCategoryModification(Integer categoryId) { + TicketCategoryModification toExistingTicketCategoryModification(Integer categoryId, int ordinal) { int capacity = Optional.ofNullable(maxTickets).orElse(0); Optional customValidityOpt = Optional.ofNullable(customValidity); @@ -245,7 +362,7 @@ TicketCategoryModification toTicketCategoryModification(Integer categoryId) { customValidityOpt.flatMap(x -> Optional.ofNullable(x.checkInTo)).map(x -> new DateTimeModification(x.toLocalDate(),x.toLocalTime())).orElse(null), customValidityOpt.flatMap(x -> Optional.ofNullable(x.validityStart)).map(x -> new DateTimeModification(x.toLocalDate(),x.toLocalTime())).orElse(null), customValidityOpt.flatMap(x -> Optional.ofNullable(x.validityEnd)).map(x -> new DateTimeModification(x.toLocalDate(),x.toLocalTime())).orElse(null), - 0, + ordinal, null, null, AlfioMetadata.empty()); @@ -253,53 +370,111 @@ TicketCategoryModification toTicketCategoryModification(Integer categoryId) { } @Getter - @AllArgsConstructor public static class CustomTicketValidityRequest { - private LocalDateTime checkInFrom; - private LocalDateTime checkInTo; - private LocalDateTime validityStart; - private LocalDateTime validityEnd; + private final LocalDateTime checkInFrom; + private final LocalDateTime checkInTo; + private final LocalDateTime validityStart; + private final LocalDateTime validityEnd; + + @JsonCreator + public CustomTicketValidityRequest(@JsonProperty("checkInFrom") LocalDateTime checkInFrom, + @JsonProperty("checkInTo") LocalDateTime checkInTo, + @JsonProperty("validityStart") LocalDateTime validityStart, + @JsonProperty("validityEnd") LocalDateTime validityEnd) { + this.checkInFrom = checkInFrom; + this.checkInTo = checkInTo; + this.validityStart = validityStart; + this.validityEnd = validityEnd; + } } @Getter - @AllArgsConstructor public static class PromoCodeRequest { - private String name; - private LocalDateTime validFrom; - private LocalDateTime validTo; - private PromoCodeDiscount.DiscountType discountType; - private int discount; + private final String name; + private final LocalDateTime validFrom; + private final LocalDateTime validTo; + private final PromoCodeDiscount.DiscountType discountType; + private final int discount; + + @JsonCreator + public PromoCodeRequest(@JsonProperty("name") String name, + @JsonProperty("validFrom") LocalDateTime validFrom, + @JsonProperty("validTo") LocalDateTime validTo, + @JsonProperty("discountType") PromoCodeDiscount.DiscountType discountType, + @JsonProperty("discount") int discount) { + this.name = name; + this.validFrom = validFrom; + this.validTo = validTo; + this.discountType = discountType; + this.discount = discount; + } } @Getter - @AllArgsConstructor public static class ExtensionSetting { - private String extensionId; - private String key; - private String value; + private final String extensionId; + private final String key; + private final String value; + + @JsonCreator + public ExtensionSetting(@JsonProperty("extensionId") String extensionId, + @JsonProperty("key") String key, + @JsonProperty("value") String value) { + this.extensionId = extensionId; + this.key = key; + this.value = value; + } } @Getter - @AllArgsConstructor public static class GroupLinkRequest { - private Integer groupId; - private LinkedGroup.Type type; - private LinkedGroup.MatchType matchType; - private Integer maxAllocation; + private final Integer groupId; + private final LinkedGroup.Type type; + private final LinkedGroup.MatchType matchType; + private final Integer maxAllocation; + + @JsonCreator + public GroupLinkRequest(@JsonProperty("groupId") Integer groupId, + @JsonProperty("type") LinkedGroup.Type type, + @JsonProperty("matchType") LinkedGroup.MatchType matchType, + @JsonProperty("maxAllocation") Integer maxAllocation) { + this.groupId = groupId; + this.type = type; + this.matchType = matchType; + this.maxAllocation = maxAllocation; + } } @Getter - @AllArgsConstructor public static class AttendeeAdditionalInfoRequest { - private Integer ordinal; - private String name; - private AdditionalInfoType type; - private Boolean required; - private List label; - private List placeholder; - private List restrictedValues; - private ContentLengthRequest contentLength; + private final Integer ordinal; + private final String name; + private final AdditionalInfoType type; + private final Boolean required; + private final List label; + private final List placeholder; + private final List restrictedValues; + private final ContentLengthRequest contentLength; + + @JsonCreator + public AttendeeAdditionalInfoRequest(@JsonProperty("ordinal") Integer ordinal, + @JsonProperty("name") String name, + @JsonProperty("type") AdditionalInfoType type, + @JsonProperty("required") Boolean required, + @JsonProperty("label") List label, + @JsonProperty("placeholder") List placeholder, + @JsonProperty("restrictedValues") List restrictedValues, + @JsonProperty("contentLength") ContentLengthRequest contentLength) { + this.ordinal = ordinal; + this.name = name; + this.type = type; + this.required = required; + this.label = label; + this.placeholder = placeholder; + this.restrictedValues = restrictedValues; + this.contentLength = contentLength; + } private EventModification.AdditionalField toAdditionalField(int ordinal) { @@ -307,9 +482,9 @@ private EventModification.AdditionalField toAdditionalField(int ordinal) { String code = type != null ? type.code : AdditionalInfoType.GENERIC_TEXT.code; Integer minLength = contentLength != null ? contentLength.min : null; Integer maxLength = contentLength != null ? contentLength.max : null; - List restrictedValues = null; + List cleanRestrictedValues = null; if(!isEmpty(this.restrictedValues)) { - restrictedValues = this.restrictedValues.stream().map(rv -> new EventModification.RestrictedValue(rv.value, rv.enabled)).collect(Collectors.toList()); + cleanRestrictedValues = this.restrictedValues.stream().map(rv -> new EventModification.RestrictedValue(rv.value, rv.enabled)).toList(); } return new EventModification.AdditionalField( @@ -321,45 +496,45 @@ private EventModification.AdditionalField toAdditionalField(int ordinal) { false, minLength, maxLength, - restrictedValues, + cleanRestrictedValues, toDescriptionMap(orEmpty(label), orEmpty(placeholder), orEmpty(this.restrictedValues)), null,//TODO: linkedAdditionalService null);//TODO: linkedCategoryIds } + + private static Map toDescriptionMap(List label, + List placeholder, + List restrictedValues) { + Map labelsByLang = label.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); + Map placeholdersByLang = placeholder.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); + Map>> valuesByLang = restrictedValues.stream() + .flatMap(rv -> rv.descriptions.stream().map(rvd -> Triple.of(rvd.lang, rv.value, rvd.body))) + .collect(Collectors.groupingBy(Triple::getLeft)); + + + Set keys = new HashSet<>(labelsByLang.keySet()); + keys.addAll(placeholdersByLang.keySet()); + keys.addAll(valuesByLang.keySet()); + + return keys.stream() + .map(lang -> { + Map rvsMap = valuesByLang.getOrDefault(lang, emptyList()).stream().collect(Collectors.toMap(Triple::getMiddle, Triple::getRight)); + return Pair.of(lang, new EventModification.Description(labelsByLang.get(lang), placeholdersByLang.get(lang), rvsMap)); + }).collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); + } } private static List orEmpty(List input) { return isEmpty(input) ? emptyList() : input; } - private static Map toDescriptionMap(List label, - List placeholder, - List restrictedValues) { - Map labelsByLang = label.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); - Map placeholdersByLang = placeholder.stream().collect(Collectors.toMap(DescriptionRequest::getLang, DescriptionRequest::getBody)); - Map>> valuesByLang = restrictedValues.stream() - .flatMap(rv -> rv.descriptions.stream().map(rvd -> Triple.of(rvd.lang, rv.value, rvd.body))) - .collect(Collectors.groupingBy(Triple::getLeft)); - - - Set keys = new HashSet<>(labelsByLang.keySet()); - keys.addAll(placeholdersByLang.keySet()); - keys.addAll(valuesByLang.keySet()); - - return keys.stream() - .map(lang -> { - Map rvsMap = valuesByLang.getOrDefault(lang, emptyList()).stream().collect(Collectors.toMap(Triple::getMiddle, Triple::getRight)); - return Pair.of(lang, new EventModification.Description(labelsByLang.get(lang), placeholdersByLang.get(lang), rvsMap)); - }).collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); - } - private static List toAdditionalFields(List additionalInfoRequests) { if(isEmpty(additionalInfoRequests)) { return emptyList(); } AtomicInteger counter = new AtomicInteger(1); - return additionalInfoRequests.stream().map(air -> air.toAdditionalField(counter.getAndIncrement())).collect(Collectors.toList()); + return additionalInfoRequests.stream().map(air -> air.toAdditionalField(counter.getAndIncrement())).toList(); } @Getter @@ -385,21 +560,30 @@ enum AdditionalInfoType { public static final Set WITH_RESTRICTED_VALUES = Set.of(AdditionalInfoType.LIST_BOX.code, AdditionalInfoType.CHECKBOX.code, AdditionalInfoType.RADIO.code); @Getter - @AllArgsConstructor public static class ContentLengthRequest { - private Integer min; - private Integer max; + private final Integer min; + private final Integer max; + + @JsonCreator + public ContentLengthRequest(@JsonProperty("min") Integer min, @JsonProperty("max") Integer max) { + this.min = min; + this.max = max; + } } @Getter - @AllArgsConstructor public static class RestrictedValueRequest { - - private String value; - private Boolean enabled; - private List descriptions; - + private final String value; + private final Boolean enabled; + private final List descriptions; + + @JsonCreator + public RestrictedValueRequest(@JsonProperty("value") String value, + @JsonProperty("enabled") Boolean enabled, + @JsonProperty("descriptions") List descriptions) { + this.value = value; + this.enabled = enabled; + this.descriptions = descriptions; + } } - - } \ No newline at end of file diff --git a/src/main/java/alfio/model/api/v1/admin/LinkedSubscriptions.java b/src/main/java/alfio/model/api/v1/admin/LinkedSubscriptions.java new file mode 100644 index 0000000000..b40016d3b8 --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/LinkedSubscriptions.java @@ -0,0 +1,39 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +public class LinkedSubscriptions { + private final String eventSlug; + private final List subscriptions; + + public LinkedSubscriptions(String eventSlug, List subscriptions) { + this.eventSlug = eventSlug; + this.subscriptions = subscriptions; + } + + public String getEventSlug() { + return eventSlug; + } + + public List getSubscriptions() { + return Objects.requireNonNullElse(subscriptions, List.of()); + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/ReservationAPICreationRequest.java b/src/main/java/alfio/model/api/v1/admin/ReservationAPICreationRequest.java new file mode 100644 index 0000000000..028cc9366d --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/ReservationAPICreationRequest.java @@ -0,0 +1,25 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +public interface ReservationAPICreationRequest { + ReservationUser getUser(); + + String getLanguage(); + + ReservationConfiguration getReservationConfiguration(); +} diff --git a/src/main/java/alfio/model/api/v1/admin/ReservationConfiguration.java b/src/main/java/alfio/model/api/v1/admin/ReservationConfiguration.java new file mode 100644 index 0000000000..45cb17427e --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/ReservationConfiguration.java @@ -0,0 +1,47 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ReservationConfiguration { + private final boolean hideContactData; + private final boolean hideConfirmationButtons; + private final boolean lockEmailEdit; + + @JsonCreator + public ReservationConfiguration(@JsonProperty("hideContactData") Boolean hideContactData, + @JsonProperty("hideConfirmationButtons") Boolean hideConfirmationButtons, + @JsonProperty("lockEmailEdit") Boolean lockEmailEdit) { + this.hideContactData = Boolean.TRUE.equals(hideContactData); + this.hideConfirmationButtons = Boolean.TRUE.equals(hideConfirmationButtons); + this.lockEmailEdit = Boolean.TRUE.equals(lockEmailEdit); + } + + public boolean isHideContactData() { + return hideContactData; + } + + public boolean isHideConfirmationButtons() { + return hideConfirmationButtons; + } + + public boolean isLockEmailEdit() { + return lockEmailEdit; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/SubscriptionDescriptorModificationRequest.java b/src/main/java/alfio/model/api/v1/admin/SubscriptionDescriptorModificationRequest.java new file mode 100644 index 0000000000..14235e638e --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/SubscriptionDescriptorModificationRequest.java @@ -0,0 +1,194 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import alfio.model.PriceContainer; +import alfio.model.api.v1.admin.subscription.CustomPeriodTerm; +import alfio.model.api.v1.admin.subscription.EntryBasedTerm; +import alfio.model.api.v1.admin.subscription.StandardPeriodTerm; +import alfio.model.api.v1.admin.subscription.SubscriptionTerm; +import alfio.model.modification.SubscriptionDescriptorModification; +import alfio.model.result.ErrorCode; +import alfio.model.result.Result; +import alfio.model.subscription.SubscriptionDescriptor; +import alfio.model.subscription.SubscriptionDescriptor.SubscriptionUsageType; +import alfio.model.transaction.PaymentProxy; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +import static alfio.util.LocaleUtil.atZone; +import static java.util.Objects.requireNonNullElse; + +public class SubscriptionDescriptorModificationRequest { + + private static final Logger log = LoggerFactory.getLogger(SubscriptionDescriptorModificationRequest.class); + public static final String TERM_STANDARD = "standard"; + public static final String TERM_NUM_ENTRIES = "numEntries"; + public static final String TERM_CUSTOM = "custom"; + + private final SubscriptionUsageType usageType; + private final SubscriptionTerm term; + + private final List title; + private final List description; + private final Integer maxAvailable; + private final LocalDateTime onSaleFrom; + private final LocalDateTime onSaleTo; + private final BigDecimal price; + private final BigDecimal taxPercentage; + private final PriceContainer.VatStatus taxPolicy; + private final String currencyCode; + private final Boolean isPublic; + private final String imageUrl; + private final String termType; + + private final String termsAndConditionsUrl; + private final String privacyPolicyUrl; + private final String timezone; + private final Boolean supportsTicketsGeneration; + private final List paymentMethods; + + + + @JsonCreator + public SubscriptionDescriptorModificationRequest(@JsonProperty("usageType") SubscriptionUsageType usageType, + @JsonProperty("termType") String termType, + @JsonTypeInfo(use= JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "termType") + @JsonSubTypes({ + // if termType is "standard", then we expect an instance of StandardPeriodTerm + @JsonSubTypes.Type(value = StandardPeriodTerm.class, name = TERM_STANDARD), + // if termType is "numEntries", then we expect an instance of EntryBasedTerm + @JsonSubTypes.Type(value = EntryBasedTerm.class, name = TERM_NUM_ENTRIES), + // if termType is "custom", then we expect an instance of CustomPeriodTerm + @JsonSubTypes.Type(value = CustomPeriodTerm.class, name = TERM_CUSTOM) + }) + @JsonProperty("term") SubscriptionTerm term, + @JsonProperty("title") List title, + @JsonProperty("description") List description, + @JsonProperty("maxAvailable") Integer maxAvailable, + @JsonProperty("onSaleFrom") LocalDateTime onSaleFrom, + @JsonProperty("onSaleTo") LocalDateTime onSaleTo, + @JsonProperty("price") BigDecimal price, + @JsonProperty("taxPercentage") BigDecimal taxPercentage, + @JsonProperty("taxPolicy") PriceContainer.VatStatus taxPolicy, + @JsonProperty("currencyCode") String currencyCode, + @JsonProperty("isPublic") Boolean isPublic, + @JsonProperty("imageUrl") String imageUrl, + @JsonProperty("termsAndConditionsUrl") String termsAndConditionsUrl, + @JsonProperty("privacyPolicyUrl") String privacyPolicyUrl, + @JsonProperty("timezone") String timezone, + @JsonProperty("supportsTicketsGeneration") Boolean supportsTicketsGeneration, + @JsonProperty("paymentMethods") List paymentMethods) { + this.usageType = usageType; + this.termType = termType; + this.term = term; + this.title = requireNonNullElse(title, List.of()); + this.description = requireNonNullElse(description, List.of()); + this.maxAvailable = maxAvailable; + this.onSaleFrom = onSaleFrom; + this.onSaleTo = onSaleTo; + this.price = price; + this.taxPercentage = taxPercentage; + this.taxPolicy = taxPolicy; + this.currencyCode = currencyCode; + this.isPublic = isPublic; + this.imageUrl = imageUrl; + this.termsAndConditionsUrl = termsAndConditionsUrl; + this.privacyPolicyUrl = privacyPolicyUrl; + this.timezone = timezone; + this.supportsTicketsGeneration = supportsTicketsGeneration; + this.paymentMethods = requireNonNullElse(paymentMethods, List.of()); + } + + public Result toDescriptorModification(UUID id, int organizationId, String fileBlobId) { + var zoneIdOptional = getZoneId(); + return new Result.Builder() + .checkPrecondition(zoneIdOptional::isPresent, ErrorCode.custom("timezone", "Timezone is mandatory")) + .checkPrecondition(() -> usageType != null, ErrorCode.custom("usageType", "UsageType is mandatory")) + .checkPrecondition(() -> term != null && term.validate(), ErrorCode.custom("term", "Term is not valid")) + .build(() -> { + var zoneId = zoneIdOptional.orElseThrow(); + return new SubscriptionDescriptorModification( + id, + title.stream().collect(Collectors.toMap(EventCreationRequest.DescriptionRequest::getLang, EventCreationRequest.DescriptionRequest::getBody)), + description.stream().collect(Collectors.toMap(EventCreationRequest.DescriptionRequest::getLang, EventCreationRequest.DescriptionRequest::getBody)), + requireNonNullElse(maxAvailable, -1), + atZone(onSaleFrom, zoneId), + atZone(onSaleTo, zoneId), + price, + taxPercentage, + taxPolicy, + currencyCode, + Boolean.TRUE.equals(isPublic), + organizationId, + requireNonNullElse(term.getNumEntries(), -1), + getValidityType(), + term.getTimeUnit(), + term.getUnits(), + atZone(term.getValidityFrom(), zoneId), + atZone(term.getValidityTo(), zoneId), + usageType, + termsAndConditionsUrl, + privacyPolicyUrl, + fileBlobId, + paymentMethods, + zoneId, + Boolean.TRUE.equals(supportsTicketsGeneration) + ); + }); + } + + private Optional getZoneId() { + if (StringUtils.isEmpty(timezone)) { + return Optional.empty(); + } + try { + return Optional.of(ZoneId.of(timezone)); + } catch(Exception ex) { + log.warn("Error while parsing timezone", ex); + return Optional.empty(); + } + } + + private SubscriptionDescriptor.SubscriptionValidityType getValidityType() { + if(TERM_STANDARD.equals(termType)) { + return SubscriptionDescriptor.SubscriptionValidityType.STANDARD; + } else if(TERM_CUSTOM.equals(termType)) { + return SubscriptionDescriptor.SubscriptionValidityType.CUSTOM; + } else if(TERM_NUM_ENTRIES.equals(termType)) { + return SubscriptionDescriptor.SubscriptionValidityType.NOT_SET; + } + return null; + } + + public String getImageUrl() { + return imageUrl; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java b/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java new file mode 100644 index 0000000000..9b15c94e53 --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/SubscriptionReservationCreationRequest.java @@ -0,0 +1,76 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin; + +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; +import alfio.model.metadata.SubscriptionMetadata; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; +import java.util.Objects; + +public class SubscriptionReservationCreationRequest implements ReservationAPICreationRequest { + private final Map metadata; + private final ReservationUser user; + private final String language; + private final ReservationConfiguration reservationConfiguration; + private final SubscriptionConfiguration subscriptionConfiguration; + + @JsonCreator + public SubscriptionReservationCreationRequest(@JsonProperty("metadata") Map metadata, + @JsonProperty("user") ReservationUser user, + @JsonProperty("language") String language, + @JsonProperty("reservationConfiguration") ReservationConfiguration reservationConfiguration, + @JsonProperty("subscriptionConfiguration") SubscriptionConfiguration subscriptionConfiguration) { + this.metadata = metadata; + this.user = user; + this.language = language; + this.reservationConfiguration = reservationConfiguration; + this.subscriptionConfiguration = Objects.requireNonNullElseGet(subscriptionConfiguration, SubscriptionConfiguration::defaultConfiguration); + } + + public Map getMetadata() { + return metadata; + } + + @Override + public ReservationUser getUser() { + return user; + } + + @Override + public String getLanguage() { + return language; + } + + @Override + public ReservationConfiguration getReservationConfiguration() { + return reservationConfiguration; + } + + public SubscriptionConfiguration getSubscriptionConfiguration() { + return subscriptionConfiguration; + } + + public SubscriptionMetadata getMetadataOrNull() { + if (metadata != null && !metadata.isEmpty()) { + return new SubscriptionMetadata(metadata, subscriptionConfiguration); + } + return null; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/ReservationCreationRequest.java b/src/main/java/alfio/model/api/v1/admin/TicketReservationCreationRequest.java similarity index 55% rename from src/main/java/alfio/model/api/v1/admin/ReservationCreationRequest.java rename to src/main/java/alfio/model/api/v1/admin/TicketReservationCreationRequest.java index 4996ff4bbf..4c687d66b8 100644 --- a/src/main/java/alfio/model/api/v1/admin/ReservationCreationRequest.java +++ b/src/main/java/alfio/model/api/v1/admin/TicketReservationCreationRequest.java @@ -18,31 +18,37 @@ import alfio.controller.form.ReservationCreate; import alfio.model.modification.AdditionalServiceReservationModification; -import alfio.model.modification.TicketReservationModification; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.StringUtils; import java.util.List; -public class ReservationCreationRequest implements ReservationCreate { +public class TicketReservationCreationRequest implements ReservationCreate, ReservationAPICreationRequest { - private final List tickets; + private final List tickets; private final List additionalServices; + private final ReservationConfiguration reservationConfiguration; private final ReservationUser user; private final String promoCode; private final String language; + private final String subscriptionId; @JsonCreator - public ReservationCreationRequest(@JsonProperty("tickets") List tickets, - @JsonProperty("additionalServices") List additionalServices, - @JsonProperty("user") ReservationUser user, - @JsonProperty("promoCode") String promoCode, - @JsonProperty("language") String language) { + public TicketReservationCreationRequest(@JsonProperty("tickets") List tickets, + @JsonProperty("additionalServices") List additionalServices, + @JsonProperty("configuration") ReservationConfiguration reservationConfiguration, + @JsonProperty("user") ReservationUser user, + @JsonProperty("promoCode") String promoCode, + @JsonProperty("language") String language, + @JsonProperty("subscriptionId") String subscriptionId) { this.tickets = tickets; this.additionalServices = additionalServices; + this.reservationConfiguration = reservationConfiguration; this.user = user; this.promoCode = promoCode; this.language = language; + this.subscriptionId = StringUtils.trimToNull(subscriptionId); } @@ -52,7 +58,7 @@ public String getPromoCode() { } @Override - public List getTickets() { + public List getTickets() { return tickets; } @@ -66,11 +72,22 @@ public String getCaptcha() { return null; } + @Override public String getLanguage() { return language; } + @Override public ReservationUser getUser() { return user; } + + @Override + public ReservationConfiguration getReservationConfiguration() { + return reservationConfiguration; + } + + public String getSubscriptionId() { + return subscriptionId; + } } diff --git a/src/main/java/alfio/model/api/v1/admin/subscription/CustomPeriodTerm.java b/src/main/java/alfio/model/api/v1/admin/subscription/CustomPeriodTerm.java new file mode 100644 index 0000000000..1c98535275 --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/subscription/CustomPeriodTerm.java @@ -0,0 +1,53 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin.subscription; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.LocalDateTime; + +public class CustomPeriodTerm implements SubscriptionTerm { + + private final LocalDateTime validityFrom; + private final LocalDateTime validityTo; + + @JsonCreator + public CustomPeriodTerm(@JsonProperty("validityFrom") LocalDateTime validityFrom, + @JsonProperty("validityTo") LocalDateTime validityTo) { + this.validityFrom = validityFrom; + this.validityTo = validityTo; + } + + @Override + public boolean validate() { + return validityFrom != null + && validityTo != null + && validityFrom.isBefore(validityTo); + } + + @Override + public LocalDateTime getValidityFrom() { + return validityFrom; + } + + @Override + public LocalDateTime getValidityTo() { + return validityTo; + } + +} diff --git a/src/main/java/alfio/model/api/v1/admin/subscription/EntryBasedTerm.java b/src/main/java/alfio/model/api/v1/admin/subscription/EntryBasedTerm.java new file mode 100644 index 0000000000..32900d06a1 --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/subscription/EntryBasedTerm.java @@ -0,0 +1,40 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin.subscription; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class EntryBasedTerm implements SubscriptionTerm { + + private final Integer numEntries; + + @JsonCreator + public EntryBasedTerm(@JsonProperty("numEntries") Integer numEntries) { + this.numEntries = numEntries; + } + + @Override + public boolean validate() { + return numEntries != null && numEntries > 0; + } + + @Override + public Integer getNumEntries() { + return numEntries; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/subscription/StandardPeriodTerm.java b/src/main/java/alfio/model/api/v1/admin/subscription/StandardPeriodTerm.java new file mode 100644 index 0000000000..e9d8207a5a --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/subscription/StandardPeriodTerm.java @@ -0,0 +1,49 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin.subscription; + +import alfio.model.subscription.SubscriptionDescriptor.SubscriptionTimeUnit; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class StandardPeriodTerm implements SubscriptionTerm { + + private final SubscriptionTimeUnit timeUnit; + private final Integer units; + + @JsonCreator + public StandardPeriodTerm(@JsonProperty("timeUnit") SubscriptionTimeUnit timeUnit, + @JsonProperty("units") Integer units) { + this.timeUnit = timeUnit; + this.units = units; + } + + @Override + public boolean validate() { + return timeUnit != null && units != null && units > 0; + } + + @Override + public SubscriptionTimeUnit getTimeUnit() { + return timeUnit; + } + + @Override + public Integer getUnits() { + return units; + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java b/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java new file mode 100644 index 0000000000..c1a05e5ad0 --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionConfiguration.java @@ -0,0 +1,42 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin.subscription; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; + +public class SubscriptionConfiguration { + /** + * Display PIN information on reservation page and PDF. Default is {@code true} + */ + private final boolean displayPin; + + @JsonCreator + public SubscriptionConfiguration(@JsonProperty("displayPin") Boolean displayPin) { + this.displayPin = Objects.requireNonNullElse(displayPin, true); + } + + public boolean isDisplayPin() { + return displayPin; + } + + public static SubscriptionConfiguration defaultConfiguration() { + return new SubscriptionConfiguration(true); + } +} diff --git a/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionTerm.java b/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionTerm.java new file mode 100644 index 0000000000..5e13d9cb2a --- /dev/null +++ b/src/main/java/alfio/model/api/v1/admin/subscription/SubscriptionTerm.java @@ -0,0 +1,48 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.api.v1.admin.subscription; + +import alfio.model.subscription.SubscriptionDescriptor; + +import java.time.LocalDateTime; + +public interface SubscriptionTerm { + /** + * Validate this subscription term + * @return {@code true} if valid + */ + boolean validate(); + + default SubscriptionDescriptor.SubscriptionTimeUnit getTimeUnit() { + return null; + } + + default Integer getUnits() { + return null; + } + default Integer getNumEntries() { + return null; + } + + default LocalDateTime getValidityFrom() { + return null; + } + + default LocalDateTime getValidityTo() { + return null; + } +} diff --git a/src/main/java/alfio/model/audit/ScanAudit.java b/src/main/java/alfio/model/audit/ScanAudit.java index b21640bc66..d0fef5e6e9 100644 --- a/src/main/java/alfio/model/audit/ScanAudit.java +++ b/src/main/java/alfio/model/audit/ScanAudit.java @@ -18,36 +18,25 @@ import alfio.manager.support.CheckInStatus; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.ZonedDateTime; +import java.time.LocalDateTime; -@Getter -public class ScanAudit { +public record ScanAudit( + @JsonProperty("ticketUuid") @Column("ticket_uuid") String ticketUuid, + @JsonProperty("scanTimestamp") @Column("scan_ts") LocalDateTime scanTimestamp, + @JsonProperty("username") @Column("username") String username, + @JsonProperty("checkInStatus") @Column("check_in_status") CheckInStatus checkInStatus, + @JsonProperty("operation") @Column("operation") ScanAudit.Operation operation) { public enum Operation { SCAN, REVERT } - private final String ticketUuid; - private final int eventId; - private final ZonedDateTime scanTimestamp; - private final String username; - private final CheckInStatus checkInStatus; - private final Operation operation; - - public ScanAudit(@Column("ticket_uuid") String ticketUuid, - @Column("event_id_fk") int eventId, - @Column("scan_ts") ZonedDateTime scanTimestamp, - @Column("username") String username, - @Column("check_in_status") CheckInStatus checkInStatus, - @Column("operation") Operation operation) { - this.ticketUuid = ticketUuid; - this.eventId = eventId; - this.scanTimestamp = scanTimestamp; - this.username = username; - this.checkInStatus = checkInStatus; - this.operation = operation; + @JsonIgnore + public String ticketUuid() { + return ticketUuid; } } diff --git a/src/main/java/alfio/model/checkin/AttendeeSearchResults.java b/src/main/java/alfio/model/checkin/AttendeeSearchResults.java new file mode 100644 index 0000000000..ac9e2e68c1 --- /dev/null +++ b/src/main/java/alfio/model/checkin/AttendeeSearchResults.java @@ -0,0 +1,116 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.checkin; + +import alfio.model.Ticket; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class AttendeeSearchResults { + private final int totalResults; + private final int checkedIn; + private final int totalPages; + private final int numPage; + private final List attendees; + + public AttendeeSearchResults(int totalResults, + int checkedIn, + int totalPages, + int numPage, + List attendees) { + this.totalResults = totalResults; + this.checkedIn = checkedIn; + this.totalPages = totalPages; + this.numPage = numPage; + this.attendees = attendees; + } + + public int getTotalResults() { + return totalResults; + } + + public int getCheckedIn() { + return checkedIn; + } + + public List getAttendees() { + return attendees; + } + + public boolean hasMorePages() { + return numPage < totalPages - 1; + } + + public int getTotalPages() { + return totalPages; + } + + public int getNumPage() { + return numPage; + } + + public static class Attendee { + private final String uuid; + private final String firstName; + private final String lastName; + private final String categoryName; + private final Map> additionalInfo; + private final Ticket.TicketStatus ticketStatus; + private final String amountToPay; + + public Attendee(String uuid, + String firstName, String lastName, String categoryName, Map> additionalInfo, Ticket.TicketStatus ticketStatus, String amountToPay) { + this.uuid = uuid; + this.firstName = firstName; + this.lastName = lastName; + this.categoryName = categoryName; + this.additionalInfo = additionalInfo; + this.ticketStatus = ticketStatus; + this.amountToPay = amountToPay; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getCategoryName() { + return categoryName; + } + + public Map> getAdditionalInfo() { + return Objects.requireNonNullElse(additionalInfo, Map.of()); + } + + public Ticket.TicketStatus getTicketStatus() { + return ticketStatus; + } + + public String getAmountToPay() { + return amountToPay; + } + + public String getUuid() { + return uuid; + } + } +} diff --git a/src/main/java/alfio/model/checkin/AttendeeSearchResultsCount.java b/src/main/java/alfio/model/checkin/AttendeeSearchResultsCount.java new file mode 100644 index 0000000000..b4bb460640 --- /dev/null +++ b/src/main/java/alfio/model/checkin/AttendeeSearchResultsCount.java @@ -0,0 +1,38 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.checkin; + +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; + +public class AttendeeSearchResultsCount { + private final int total; + private final int checkedIn; + + public AttendeeSearchResultsCount(@Column("total") int total, + @Column("checked_in") int checkedIn) { + this.total = total; + this.checkedIn = checkedIn; + } + + public int getTotal() { + return total; + } + + public int getCheckedIn() { + return checkedIn; + } +} diff --git a/src/main/java/alfio/model/checkin/CheckInFullInfo.java b/src/main/java/alfio/model/checkin/CheckInFullInfo.java new file mode 100644 index 0000000000..569d59fcaf --- /dev/null +++ b/src/main/java/alfio/model/checkin/CheckInFullInfo.java @@ -0,0 +1,162 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.checkin; + +import alfio.model.*; +import alfio.model.metadata.AlfioMetadata; +import alfio.model.support.Array; +import alfio.model.support.JSONData; +import alfio.model.transaction.PaymentProxy; +import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; +import lombok.Getter; + +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@Getter +public class CheckInFullInfo { + + private final Ticket ticket; + private final TicketReservation ticketReservation; + private final BillingDetails billingDetails; + private final TicketCategory ticketCategory; + private final AlfioMetadata categoryMetadata; + private final Map> ticketAdditionalInfo; + private final EventWithCheckInInfo eventWithCheckInInfo; + + + public CheckInFullInfo(@Column("t_id") int id, + @Column("t_uuid") String uuid, + @Column("t_creation") ZonedDateTime creation, + @Column("t_category_id") int categoryId, + @Column("t_status") String status, + @Column("t_event_id") int eventId, + @Column("t_src_price_cts") int ticketSrcPriceCts, + @Column("t_final_price_cts") int ticketFinalPriceCts, + @Column("t_vat_cts") int ticketVatCts, + @Column("t_discount_cts") int ticketDiscountCts, + @Column("t_tickets_reservation_id") String ticketsReservationId, + @Column("t_full_name") String fullName, + @Column("t_first_name") String firstName, + @Column("t_last_name") String lastName, + @Column("t_email_address") String email, + @Column("t_locked_assignment") boolean lockedAssignment, + @Column("t_user_language") String userLanguage, + @Column("t_ext_reference") String extReference, + @Column("t_currency_code") String currencyCode, + @Column("t_tags") @Array List ticketTags, + @Column("t_subscription_id") UUID ticketSubscriptionId, + @Column("t_vat_status") PriceContainer.VatStatus ticketVatStatus, + // + @Column("tr_id") String trId, + @Column("tr_validity") Date trValidity, + @Column("tr_status") TicketReservation.TicketReservationStatus trStatus, + @Column("tr_full_name") String trFullName, + @Column("tr_first_name") String trFirstName, + @Column("tr_last_name") String trLastName, + @Column("tr_email_address") String trEmail, + @Column("tr_billing_address") String trBillingAddress, + @Column("tr_confirmation_ts") ZonedDateTime trConfirmationTimestamp, + @Column("tr_latest_reminder_ts") ZonedDateTime trLatestReminder, + @Column("tr_payment_method") PaymentProxy trPaymentMethod, + @Column("tr_offline_payment_reminder_sent") Boolean trReminderSent, + @Column("tr_promo_code_id_fk") Integer trPromoCodeDiscountId, + @Column("tr_automatic") boolean trAutomatic, + @Column("tr_user_language") String resUserLanguage, + @Column("tr_direct_assignment") boolean directAssignment, + @Column("tr_invoice_number") String invoiceNumber, + @Column("tr_invoice_model") String invoiceModel, + @Column("tr_vat_status") PriceContainer.VatStatus reservationVatStatus, + @Column("tr_vat_nr") String vatNr, + @Column("tr_vat_country") String vatCountry, + @Column("tr_invoice_requested") boolean invoiceRequested, + @Column("tr_used_vat_percent") BigDecimal usedVatPercent, + @Column("tr_vat_included") Boolean vatIncluded, + @Column("tr_creation_ts") ZonedDateTime reservationCreationTimestamp, + @Column("tr_customer_reference") String customerReference, + @Column("tr_registration_ts") ZonedDateTime reservationRegistrationTimestamp, + // + @Column("tr_billing_address_company") String billingAddressCompany, + @Column("tr_billing_address_line1") String billingAddressLine1, + @Column("tr_billing_address_line2") String billingAddressLine2, + @Column("tr_billing_address_city") String billingAddressCity, + @Column("tr_billing_address_state") String billingAddressState, + @Column("tr_billing_address_zip") String billingAddressZip, + @Column("tr_invoicing_additional_information") @JSONData TicketReservationInvoicingAdditionalInfo invoicingAdditionalInfo, + + @Column("tr_src_price_cts") int reservationSrcPriceCts, + @Column("tr_final_price_cts") int reservationFinalPriceCts, + @Column("tr_vat_cts") int reservationVatCts, + @Column("tr_discount_cts") int reservationDiscountCts, + @Column("tr_currency_code") String reservationCurrencyCode, + // + @Column("tc_id") int tcId, + @Column("tc_inception") ZonedDateTime tcUtcInception, + @Column("tc_expiration") ZonedDateTime tcUtcExpiration, + @Column("tc_max_tickets") int tcMaxTickets, + @Column("tc_name") String tcName, + @Column("tc_src_price_cts") int tcSrcPriceCts, + @Column("tc_access_restricted") boolean tcAccessRestricted, + @Column("tc_tc_status") TicketCategory.Status tcStatus, + @Column("tc_event_id") int tcEventId, + @Column("tc_bounded") boolean bounded, + @Column("tc_category_code") String code, + @Column("tc_valid_checkin_from") ZonedDateTime validCheckInFrom, + @Column("tc_valid_checkin_to") ZonedDateTime validCheckInTo, + @Column("tc_ticket_validity_start") ZonedDateTime ticketValidityStart, + @Column("tc_ticket_validity_end") ZonedDateTime ticketValidityEnd, + @Column("tc_ordinal") int ordinal, + @Column("tc_ticket_checkin_strategy") TicketCategory.TicketCheckInStrategy ticketCheckInStrategy, + @Column("tc_metadata") @JSONData AlfioMetadata categoryMetadata, + @Column("tc_ticket_access_type") TicketCategory.TicketAccessType ticketAccessType, + + @Column("e_format") Event.EventFormat eventFormat, + @Column("e_short_name") String eventShortName, + @Column("e_display_name") String eventDisplayName, + @Column("e_start_ts") ZonedDateTime eventStartTs, + @Column("e_end_ts") ZonedDateTime eventEndTs, + @Column("e_time_zone") String timezone, + @Column("e_private_key") String eventPrivateKey, + @Column("e_org_id") int eventOrgId, + @Column("e_metadata") @JSONData AlfioMetadata eventMetadata, + @Column("e_locales") int locales, + @Column("e_version") String eventVersion, + + @Column("tai_additional_info") @JSONData Map> ticketAdditionalInfo + ) { + + this.ticket = new Ticket(id, uuid, creation, categoryId, status, eventId, ticketsReservationId, fullName, firstName, lastName, email, + lockedAssignment, userLanguage, ticketSrcPriceCts, ticketFinalPriceCts, ticketVatCts, ticketDiscountCts, extReference, currencyCode, + ticketTags, ticketSubscriptionId, ticketVatStatus); + this.ticketReservation = new TicketReservation(trId, trValidity, trStatus, trFullName, trFirstName, trLastName, trEmail, trBillingAddress, + trConfirmationTimestamp, trLatestReminder, trPaymentMethod, trReminderSent, trPromoCodeDiscountId, trAutomatic, resUserLanguage, + directAssignment, invoiceNumber, invoiceModel, reservationVatStatus, vatNr, vatCountry, invoiceRequested, usedVatPercent, vatIncluded, reservationCreationTimestamp, customerReference, + reservationRegistrationTimestamp, reservationSrcPriceCts, reservationFinalPriceCts, reservationVatCts, reservationDiscountCts, reservationCurrencyCode); + this.ticketCategory = new TicketCategory(tcId, tcUtcInception, tcUtcExpiration, tcMaxTickets, tcName, + tcAccessRestricted, tcStatus, tcEventId, bounded, tcSrcPriceCts, code, validCheckInFrom, validCheckInTo, + ticketValidityStart, ticketValidityEnd, currencyCode, ordinal, ticketCheckInStrategy, ticketAccessType); + + this.categoryMetadata = categoryMetadata; + this.billingDetails = new BillingDetails(billingAddressCompany, billingAddressLine1, billingAddressLine2, billingAddressZip, billingAddressCity, billingAddressState, vatCountry, vatNr, invoicingAdditionalInfo); + this.eventWithCheckInInfo = new EventWithCheckInInfo(eventId, eventFormat, eventShortName, eventDisplayName, eventStartTs, eventEndTs, timezone, eventPrivateKey, eventOrgId, eventMetadata, locales, eventVersion); + this.ticketAdditionalInfo = ticketAdditionalInfo; + } +} diff --git a/src/main/java/alfio/model/checkin/EventWithCheckInInfo.java b/src/main/java/alfio/model/checkin/EventWithCheckInInfo.java index 48d1b30ffa..fa5f4f793d 100644 --- a/src/main/java/alfio/model/checkin/EventWithCheckInInfo.java +++ b/src/main/java/alfio/model/checkin/EventWithCheckInInfo.java @@ -19,6 +19,7 @@ import alfio.model.*; import alfio.model.metadata.AlfioMetadata; import alfio.model.support.JSONData; +import alfio.util.EventUtil; import lombok.Getter; import org.apache.commons.lang3.tuple.Pair; @@ -41,6 +42,7 @@ public class EventWithCheckInInfo extends EventAndOrganizationId implements Even private final String privateKey; private final AlfioMetadata metadata; private final List contentLanguages; + private final String version; public EventWithCheckInInfo(@Column("id") int id, @@ -53,7 +55,8 @@ public EventWithCheckInInfo(@Column("id") int id, @Column("private_key") String privateKey, @Column("org_id") int organizationId, @Column("metadata") @JSONData AlfioMetadata metadata, - @Column("locales") int locales) { + @Column("locales") int locales, + @Column("version") String version) { super(id, organizationId); this.zoneId = ZoneId.of(timezone); this.format = format; @@ -64,6 +67,7 @@ public EventWithCheckInInfo(@Column("id") int id, this.privateKey = privateKey; this.metadata = metadata; this.contentLanguages = ContentLanguage.findAllFor(locales); + this.version = version; } public boolean isOnline() { @@ -94,4 +98,9 @@ public BigDecimal getVat() { public List getContentLanguages() { return contentLanguages; } + + @Override + public boolean supportsQRCodeCaseInsensitive() { + return EventUtil.supportsCaseInsensitiveQRCode(version); + } } diff --git a/src/main/java/alfio/model/checkin/OnlineCheckInFullInfo.java b/src/main/java/alfio/model/checkin/OnlineCheckInFullInfo.java deleted file mode 100644 index 1594eb8c90..0000000000 --- a/src/main/java/alfio/model/checkin/OnlineCheckInFullInfo.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * This file is part of alf.io. - * - * alf.io is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * alf.io is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with alf.io. If not, see . - */ -package alfio.model.checkin; - -import alfio.model.*; -import alfio.model.metadata.AlfioMetadata; -import alfio.model.support.Array; -import alfio.model.support.JSONData; -import alfio.model.transaction.PaymentProxy; -import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; - -import java.math.BigDecimal; -import java.time.ZonedDateTime; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -@Getter -public class OnlineCheckInFullInfo { - - private final Ticket ticket; - private final TicketReservation ticketReservation; - private final BillingDetails billingDetails; - private final TicketCategory ticketCategory; - private final AlfioMetadata categoryMetadata; - private final Map> ticketAdditionalInfo; - private final EventWithCheckInInfo eventWithCheckInInfo; - - - public OnlineCheckInFullInfo(@Column("t_id") int id, - @Column("t_uuid") String uuid, - @Column("t_creation") ZonedDateTime creation, - @Column("t_category_id") int categoryId, - @Column("t_status") String status, - @Column("t_event_id") int eventId, - @Column("t_src_price_cts") int ticketSrcPriceCts, - @Column("t_final_price_cts") int ticketFinalPriceCts, - @Column("t_vat_cts") int ticketVatCts, - @Column("t_discount_cts") int ticketDiscountCts, - @Column("t_tickets_reservation_id") String ticketsReservationId, - @Column("t_full_name") String fullName, - @Column("t_first_name") String firstName, - @Column("t_last_name") String lastName, - @Column("t_email_address") String email, - @Column("t_locked_assignment") boolean lockedAssignment, - @Column("t_user_language") String userLanguage, - @Column("t_ext_reference") String extReference, - @Column("t_currency_code") String currencyCode, - @Column("t_tags") @Array List ticketTags, - @Column("t_subscription_id") UUID ticketSubscriptionId, - @Column("t_vat_status") PriceContainer.VatStatus ticketVatStatus, - // - @Column("tr_id") String trId, - @Column("tr_validity") Date trValidity, - @Column("tr_status") TicketReservation.TicketReservationStatus trStatus, - @Column("tr_full_name") String trFullName, - @Column("tr_first_name") String trFirstName, - @Column("tr_last_name") String trLastName, - @Column("tr_email_address") String trEmail, - @Column("tr_billing_address") String trBillingAddress, - @Column("tr_confirmation_ts") ZonedDateTime trConfirmationTimestamp, - @Column("tr_latest_reminder_ts") ZonedDateTime trLatestReminder, - @Column("tr_payment_method") PaymentProxy trPaymentMethod, - @Column("tr_offline_payment_reminder_sent") Boolean trReminderSent, - @Column("tr_promo_code_id_fk") Integer trPromoCodeDiscountId, - @Column("tr_automatic") boolean trAutomatic, - @Column("tr_user_language") String resUserLanguage, - @Column("tr_direct_assignment") boolean directAssignment, - @Column("tr_invoice_number") String invoiceNumber, - @Column("tr_invoice_model") String invoiceModel, - @Column("tr_vat_status") PriceContainer.VatStatus reservationVatStatus, - @Column("tr_vat_nr") String vatNr, - @Column("tr_vat_country") String vatCountry, - @Column("tr_invoice_requested") boolean invoiceRequested, - @Column("tr_used_vat_percent") BigDecimal usedVatPercent, - @Column("tr_vat_included") Boolean vatIncluded, - @Column("tr_creation_ts") ZonedDateTime reservationCreationTimestamp, - @Column("tr_customer_reference") String customerReference, - @Column("tr_registration_ts") ZonedDateTime reservationRegistrationTimestamp, - // - @Column("tr_billing_address_company") String billingAddressCompany, - @Column("tr_billing_address_line1") String billingAddressLine1, - @Column("tr_billing_address_line2") String billingAddressLine2, - @Column("tr_billing_address_city") String billingAddressCity, - @Column("tr_billing_address_state") String billingAddressState, - @Column("tr_billing_address_zip") String billingAddressZip, - @Column("tr_invoicing_additional_information") @JSONData TicketReservationInvoicingAdditionalInfo invoicingAdditionalInfo, - - @Column("tr_src_price_cts") int reservationSrcPriceCts, - @Column("tr_final_price_cts") int reservationFinalPriceCts, - @Column("tr_vat_cts") int reservationVatCts, - @Column("tr_discount_cts") int reservationDiscountCts, - @Column("tr_currency_code") String reservationCurrencyCode, - // - @Column("tc_id") int tcId, - @Column("tc_inception") ZonedDateTime tcUtcInception, - @Column("tc_expiration") ZonedDateTime tcUtcExpiration, - @Column("tc_max_tickets") int tcMaxTickets, - @Column("tc_name") String tcName, - @Column("tc_src_price_cts") int tcSrcPriceCts, - @Column("tc_access_restricted") boolean tcAccessRestricted, - @Column("tc_tc_status") TicketCategory.Status tcStatus, - @Column("tc_event_id") int tcEventId, - @Column("tc_bounded") boolean bounded, - @Column("tc_category_code") String code, - @Column("tc_valid_checkin_from") ZonedDateTime validCheckInFrom, - @Column("tc_valid_checkin_to") ZonedDateTime validCheckInTo, - @Column("tc_ticket_validity_start") ZonedDateTime ticketValidityStart, - @Column("tc_ticket_validity_end") ZonedDateTime ticketValidityEnd, - @Column("tc_ordinal") int ordinal, - @Column("tc_ticket_checkin_strategy") TicketCategory.TicketCheckInStrategy ticketCheckInStrategy, - @Column("tc_metadata") @JSONData AlfioMetadata categoryMetadata, - @Column("tc_ticket_access_type") TicketCategory.TicketAccessType ticketAccessType, - - @Column("e_format") Event.EventFormat eventFormat, - @Column("e_short_name") String eventShortName, - @Column("e_display_name") String eventDisplayName, - @Column("e_start_ts") ZonedDateTime eventStartTs, - @Column("e_end_ts") ZonedDateTime eventEndTs, - @Column("e_time_zone") String timezone, - @Column("e_private_key") String eventPrivateKey, - @Column("e_org_id") int eventOrgId, - @Column("e_metadata") @JSONData AlfioMetadata eventMetadata, - @Column("e_locales") int locales, - - @Column("tai_additional_info") @JSONData Map> ticketAdditionalInfo - ) { - - this.ticket = new Ticket(id, uuid, creation, categoryId, status, eventId, ticketsReservationId, fullName, firstName, lastName, email, - lockedAssignment, userLanguage, ticketSrcPriceCts, ticketFinalPriceCts, ticketVatCts, ticketDiscountCts, extReference, currencyCode, - ticketTags, ticketSubscriptionId, ticketVatStatus); - this.ticketReservation = new TicketReservation(trId, trValidity, trStatus, trFullName, trFirstName, trLastName, trEmail, trBillingAddress, - trConfirmationTimestamp, trLatestReminder, trPaymentMethod, trReminderSent, trPromoCodeDiscountId, trAutomatic, resUserLanguage, - directAssignment, invoiceNumber, invoiceModel, reservationVatStatus, vatNr, vatCountry, invoiceRequested, usedVatPercent, vatIncluded, reservationCreationTimestamp, customerReference, - reservationRegistrationTimestamp, reservationSrcPriceCts, reservationFinalPriceCts, reservationVatCts, reservationDiscountCts, reservationCurrencyCode); - this.ticketCategory = new TicketCategory(tcId, tcUtcInception, tcUtcExpiration, tcMaxTickets, tcName, - tcAccessRestricted, tcStatus, tcEventId, bounded, tcSrcPriceCts, code, validCheckInFrom, validCheckInTo, - ticketValidityStart, ticketValidityEnd, currencyCode, ordinal, ticketCheckInStrategy, ticketAccessType); - - this.categoryMetadata = categoryMetadata; - this.billingDetails = new BillingDetails(billingAddressCompany, billingAddressLine1, billingAddressLine2, billingAddressZip, billingAddressCity, billingAddressState, vatCountry, vatNr, invoicingAdditionalInfo); - this.eventWithCheckInInfo = new EventWithCheckInInfo(eventId, eventFormat, eventShortName, eventDisplayName, eventStartTs, eventEndTs, timezone, eventPrivateKey, eventOrgId, eventMetadata, locales); - this.ticketAdditionalInfo = ticketAdditionalInfo; - } -} diff --git a/src/main/java/alfio/model/decorator/AdditionalServiceItemPriceContainer.java b/src/main/java/alfio/model/decorator/AdditionalServiceItemPriceContainer.java index cf4c8d774d..e7e5254fa8 100644 --- a/src/main/java/alfio/model/decorator/AdditionalServiceItemPriceContainer.java +++ b/src/main/java/alfio/model/decorator/AdditionalServiceItemPriceContainer.java @@ -18,14 +18,12 @@ import alfio.model.*; import alfio.util.MonetaryUtil; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; import java.math.BigDecimal; import java.util.Optional; -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) + public class AdditionalServiceItemPriceContainer implements SummaryPriceContainer { @Delegate(excludes = PriceContainer.class) private final AdditionalServiceItem additionalServiceItem; @@ -35,6 +33,20 @@ public class AdditionalServiceItemPriceContainer implements SummaryPriceContaine private final VatStatus eventVatStatus; private final BigDecimal eventVatPercentage; + private AdditionalServiceItemPriceContainer(AdditionalServiceItem additionalServiceItem, + AdditionalService additionalService, + String currencyCode, + PromoCodeDiscount discount, + VatStatus eventVatStatus, + BigDecimal eventVatPercentage) { + this.additionalServiceItem = additionalServiceItem; + this.additionalService = additionalService; + this.currencyCode = currencyCode; + this.discount = discount; + this.eventVatStatus = eventVatStatus; + this.eventVatPercentage = eventVatPercentage; + } + @Override public int getSrcPriceCts() { return Optional.ofNullable(additionalServiceItem.getSrcPriceCts()).orElse(0); diff --git a/src/main/java/alfio/model/decorator/AdditionalServicePriceContainer.java b/src/main/java/alfio/model/decorator/AdditionalServicePriceContainer.java index 2f6d31902a..efeb0af13b 100644 --- a/src/main/java/alfio/model/decorator/AdditionalServicePriceContainer.java +++ b/src/main/java/alfio/model/decorator/AdditionalServicePriceContainer.java @@ -21,13 +21,10 @@ import alfio.model.PriceContainer; import alfio.model.PromoCodeDiscount; import alfio.util.MonetaryUtil; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; import java.math.BigDecimal; import java.util.Optional; -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class AdditionalServicePriceContainer implements PriceContainer { private final BigDecimal customAmount; @@ -37,6 +34,20 @@ public class AdditionalServicePriceContainer implements PriceContainer { private final BigDecimal vatPercentage; private final VatStatus vatStatus; + private AdditionalServicePriceContainer(BigDecimal customAmount, + AdditionalService additionalService, + PromoCodeDiscount promoCodeDiscount, + String currencyCode, + BigDecimal vatPercentage, + VatStatus vatStatus) { + this.customAmount = customAmount; + this.additionalService = additionalService; + this.promoCodeDiscount = promoCodeDiscount; + this.currencyCode = currencyCode; + this.vatPercentage = vatPercentage; + this.vatStatus = vatStatus; + } + @Override public int getSrcPriceCts() { if(additionalService.isFixPrice()) { diff --git a/src/main/java/alfio/model/decorator/TicketPriceContainer.java b/src/main/java/alfio/model/decorator/TicketPriceContainer.java index 50a5750362..3d76ebce6e 100644 --- a/src/main/java/alfio/model/decorator/TicketPriceContainer.java +++ b/src/main/java/alfio/model/decorator/TicketPriceContainer.java @@ -19,17 +19,12 @@ import alfio.model.PromoCodeDiscount; import alfio.model.SummaryPriceContainer; import alfio.model.Ticket; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; import org.apache.commons.lang3.ObjectUtils; import java.math.BigDecimal; import java.util.Optional; -import static alfio.util.MonetaryUtil.unitToCents; - -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class TicketPriceContainer implements SummaryPriceContainer { @Delegate(excludes = OverridePriceContainer.class) @@ -38,6 +33,16 @@ public class TicketPriceContainer implements SummaryPriceContainer { private final BigDecimal vatPercentage; private final VatStatus vatStatus; + private TicketPriceContainer(Ticket ticket, + PromoCodeDiscount promoCodeDiscount, + BigDecimal vatPercentage, + VatStatus vatStatus) { + this.ticket = ticket; + this.promoCodeDiscount = promoCodeDiscount; + this.vatPercentage = vatPercentage; + this.vatStatus = vatStatus; + } + @Override public Optional getDiscount() { return Optional.ofNullable(promoCodeDiscount) @@ -68,7 +73,9 @@ public static TicketPriceContainer from(Ticket t, VatStatus reservationVatStatus @Override public BigDecimal getTaxablePrice() { - if(vatStatus != VatStatus.INCLUDED_EXEMPT && vatStatus != VatStatus.NOT_INCLUDED_EXEMPT) { + if(vatStatus != VatStatus.INCLUDED_EXEMPT + && vatStatus != VatStatus.NOT_INCLUDED_EXEMPT + && vatStatus != VatStatus.CUSTOM_NOT_INCLUDED_EXEMPT) { return SummaryPriceContainer.super.getTaxablePrice(); } return BigDecimal.ZERO; diff --git a/src/main/java/alfio/model/extension/CreditNoteGeneration.java b/src/main/java/alfio/model/extension/CreditNoteGeneration.java index 56ff48bb65..e17506328a 100644 --- a/src/main/java/alfio/model/extension/CreditNoteGeneration.java +++ b/src/main/java/alfio/model/extension/CreditNoteGeneration.java @@ -17,9 +17,14 @@ package alfio.model.extension; -import lombok.Data; - -@Data public class CreditNoteGeneration { private String creditNoteNumber; + + public String getCreditNoteNumber() { + return creditNoteNumber; + } + + public void setCreditNoteNumber(String creditNoteNumber) { + this.creditNoteNumber = creditNoteNumber; + } } diff --git a/src/main/java/alfio/model/extension/CustomTaxPolicy.java b/src/main/java/alfio/model/extension/CustomTaxPolicy.java new file mode 100644 index 0000000000..955baec5fc --- /dev/null +++ b/src/main/java/alfio/model/extension/CustomTaxPolicy.java @@ -0,0 +1,78 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.extension; + +import alfio.model.PriceContainer; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class CustomTaxPolicy { + + private final Set ticketPolicies; + + @JsonCreator + public CustomTaxPolicy(@JsonProperty("ticketPolicies") List ticketPolicies) { + this.ticketPolicies = new HashSet<>(ticketPolicies); + } + + public Set getTicketPolicies() { + return ticketPolicies; + } + + public static class TicketTaxPolicy implements Comparable { + private final String uuid; + private final PriceContainer.VatStatus taxPolicy; + + @JsonCreator + public TicketTaxPolicy(@JsonProperty("uuid") String uuid, + @JsonProperty("taxPolicy") PriceContainer.VatStatus taxPolicy) { + this.uuid = Objects.requireNonNull(uuid); + this.taxPolicy = taxPolicy; + } + + public PriceContainer.VatStatus getTaxPolicy() { + return taxPolicy; + } + + public String getUuid() { + return uuid; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TicketTaxPolicy)) return false; + TicketTaxPolicy that = (TicketTaxPolicy) o; + return Objects.equals(this.uuid, that.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(uuid); + } + + @Override + public int compareTo(TicketTaxPolicy o) { + return this.equals(o) ? 0 : this.uuid.compareTo(o.uuid); + } + } +} diff --git a/src/main/java/alfio/model/extension/DynamicDiscount.java b/src/main/java/alfio/model/extension/DynamicDiscount.java index 199fe46c75..41809aab33 100644 --- a/src/main/java/alfio/model/extension/DynamicDiscount.java +++ b/src/main/java/alfio/model/extension/DynamicDiscount.java @@ -17,17 +17,38 @@ package alfio.model.extension; import alfio.model.PromoCodeDiscount; -import lombok.Data; import java.util.Arrays; -@Data public class DynamicDiscount { private String amount; private String type; private String code; + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getAmount() { + return amount; + } public PromoCodeDiscount.DiscountType getDiscountType() { return Arrays.stream(PromoCodeDiscount.DiscountType.values()) diff --git a/src/main/java/alfio/model/extension/InvoiceGeneration.java b/src/main/java/alfio/model/extension/InvoiceGeneration.java index ae2ca1a46d..9fa4ed018d 100644 --- a/src/main/java/alfio/model/extension/InvoiceGeneration.java +++ b/src/main/java/alfio/model/extension/InvoiceGeneration.java @@ -17,9 +17,14 @@ package alfio.model.extension; -import lombok.Data; - -@Data public class InvoiceGeneration { private String invoiceNumber; + + public String getInvoiceNumber() { + return invoiceNumber; + } + + public void setInvoiceNumber(String invoiceNumber) { + this.invoiceNumber = invoiceNumber; + } } diff --git a/src/main/java/alfio/model/extension/PdfGenerationResult.java b/src/main/java/alfio/model/extension/PdfGenerationResult.java index f3b8e628a7..d8680ea23c 100644 --- a/src/main/java/alfio/model/extension/PdfGenerationResult.java +++ b/src/main/java/alfio/model/extension/PdfGenerationResult.java @@ -16,12 +16,7 @@ */ package alfio.model.extension; -import lombok.Data; - -@Data -public class PdfGenerationResult { - private final String tempFilePath; - +public record PdfGenerationResult(String tempFilePath) { public boolean isEmpty() { return tempFilePath == null || tempFilePath.isEmpty(); } diff --git a/src/main/java/alfio/model/metadata/AlfioMetadata.java b/src/main/java/alfio/model/metadata/AlfioMetadata.java index 4e17d5ec69..30d568bf33 100644 --- a/src/main/java/alfio/model/metadata/AlfioMetadata.java +++ b/src/main/java/alfio/model/metadata/AlfioMetadata.java @@ -25,21 +25,39 @@ @Getter public class AlfioMetadata { + private static final AlfioMetadata EMPTY = new AlfioMetadata(null, Map.of(), List.of(), null); private final OnlineConfiguration onlineConfiguration; // list of requirements for participants, e.g. software private final Map requirementsDescriptions; private final List conditionsToBeAccepted; + private final String copiedFrom; @JsonCreator public AlfioMetadata(@JsonProperty("onlineConfiguration") OnlineConfiguration onlineConfiguration, @JsonProperty("requirementsDescriptions") Map requirementsDescriptions, - @JsonProperty("conditionsToBeAccepted") List conditionsToBeAccepted) { + @JsonProperty("conditionsToBeAccepted") List conditionsToBeAccepted, + @JsonProperty("copiedFrom") String copiedFrom) { this.onlineConfiguration = onlineConfiguration; this.requirementsDescriptions = requirementsDescriptions; this.conditionsToBeAccepted = conditionsToBeAccepted; + this.copiedFrom = copiedFrom; } public static AlfioMetadata empty() { - return new AlfioMetadata(null, Map.of(), List.of()); + return EMPTY; + } + + /** + * Returns a merged version of the metadata. + * The "copiedFrom" attribute will not be overridden by {@code other} + * @param other metadata to merge + * @return merged metadata + */ + public AlfioMetadata merge(AlfioMetadata other) { + return new AlfioMetadata( + other.onlineConfiguration, + other.requirementsDescriptions, + other.conditionsToBeAccepted, + copiedFrom); } } diff --git a/src/main/java/alfio/model/metadata/ConditionsLink.java b/src/main/java/alfio/model/metadata/ConditionsLink.java index 9fbcfbe243..3e0ded5ef6 100644 --- a/src/main/java/alfio/model/metadata/ConditionsLink.java +++ b/src/main/java/alfio/model/metadata/ConditionsLink.java @@ -25,7 +25,7 @@ @Getter public class ConditionsLink { enum Type { - TERMS_OF_PARTICIPATION, PRIVACY_POLICY, CUSTOM; + TERMS_OF_PARTICIPATION, PRIVACY_POLICY, CUSTOM } private final Type type; diff --git a/src/main/java/alfio/model/metadata/JoinLink.java b/src/main/java/alfio/model/metadata/JoinLink.java index dd88ecf23c..b4348973d6 100644 --- a/src/main/java/alfio/model/metadata/JoinLink.java +++ b/src/main/java/alfio/model/metadata/JoinLink.java @@ -18,31 +18,15 @@ import alfio.model.LocalizedContent; import alfio.util.EventUtil; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; import java.time.LocalDateTime; import java.util.Map; -import java.util.Objects; -@Getter -public class JoinLink { - private final String link; - private final LocalDateTime validFrom; - private final LocalDateTime validTo; - private final Map linkText; - - @JsonCreator - public JoinLink(@JsonProperty("link") String link, - @JsonProperty("validFrom") LocalDateTime validFrom, - @JsonProperty("validTo") LocalDateTime validTo, - @JsonProperty("linkText") Map linkText) { - this.link = link; - this.validFrom = validFrom; - this.validTo = validTo; - this.linkText = Objects.requireNonNullElse(linkText, Map.of()); - } +public record JoinLink(@JsonProperty("link") String link, + @JsonProperty("validFrom") LocalDateTime validFrom, + @JsonProperty("validTo") LocalDateTime validTo, + @JsonProperty("linkText") Map linkText) { public boolean hasLinkText() { return !linkText.isEmpty(); @@ -51,24 +35,4 @@ public boolean hasLinkText() { public String getLocalizedText(String lang, LocalizedContent fallback) { return EventUtil.getLocalizedMessage(linkText, lang, fallback); } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - JoinLink joinLink = (JoinLink) o; - return Objects.equals(link, joinLink.link) - && Objects.equals(validFrom, joinLink.validFrom) - && Objects.equals(validTo, joinLink.validTo) - && linkText.equals(joinLink.linkText); - } - - @Override - public int hashCode() { - return Objects.hash(link, validFrom, validTo, linkText); - } } diff --git a/src/main/java/alfio/model/metadata/SubscriptionMetadata.java b/src/main/java/alfio/model/metadata/SubscriptionMetadata.java new file mode 100644 index 0000000000..ef3fc9007b --- /dev/null +++ b/src/main/java/alfio/model/metadata/SubscriptionMetadata.java @@ -0,0 +1,50 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.metadata; + +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; +import java.util.Objects; + +public class SubscriptionMetadata { + + private final Map properties; + private final SubscriptionConfiguration configuration; + + @JsonCreator + public SubscriptionMetadata(@JsonProperty("properties") Map properties, + @JsonProperty("configuration") SubscriptionConfiguration configuration) { + this.properties = Objects.requireNonNullElse(properties, Map.of()); + this.configuration = Objects.requireNonNullElseGet(configuration, SubscriptionConfiguration::defaultConfiguration); + } + + + public Map getProperties() { + return properties; + } + + public SubscriptionConfiguration getConfiguration() { + return configuration; + } + + public static SubscriptionMetadata empty() { + return new SubscriptionMetadata(null, null); + } +} diff --git a/src/main/java/alfio/model/metadata/TicketMetadata.java b/src/main/java/alfio/model/metadata/TicketMetadata.java index 8425c46848..e54f271970 100644 --- a/src/main/java/alfio/model/metadata/TicketMetadata.java +++ b/src/main/java/alfio/model/metadata/TicketMetadata.java @@ -80,6 +80,9 @@ public int hashCode() { public static TicketMetadata empty() { return new TicketMetadata(null, null, Map.of()); } + public TicketMetadata withAttributes(Map attributes) { + return new TicketMetadata(joinLink, Map.copyOf(linkDescription), Map.copyOf(attributes)); + } public static TicketMetadata copyOf(TicketMetadata src) { if (src != null) { diff --git a/src/main/java/alfio/model/modification/AttendeeData.java b/src/main/java/alfio/model/modification/AttendeeData.java new file mode 100644 index 0000000000..8fcd833589 --- /dev/null +++ b/src/main/java/alfio/model/modification/AttendeeData.java @@ -0,0 +1,71 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.modification; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; + +public class AttendeeData { + private final String firstName; + private final String lastName; + private final String email; + private final Map metadata; + + @JsonCreator + public AttendeeData(@JsonProperty("firstName") String firstName, + @JsonProperty("lastName") String lastName, + @JsonProperty("email") String email, + @JsonProperty("metadata") Map metadata) { + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.metadata = metadata; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public Map getMetadata() { + return metadata; + } + + public boolean hasMetadata() { + return metadata != null; + } + + public boolean hasContactData() { + return StringUtils.isNotBlank(firstName) + || StringUtils.isNotBlank(lastName) + || StringUtils.isNotBlank(email); + } + + public static AttendeeData empty() { + return new AttendeeData(null, null, null, null); + } +} diff --git a/src/main/java/alfio/model/modification/EventModification.java b/src/main/java/alfio/model/modification/EventModification.java index b85949395f..de6bb1dfe5 100644 --- a/src/main/java/alfio/model/modification/EventModification.java +++ b/src/main/java/alfio/model/modification/EventModification.java @@ -390,7 +390,7 @@ public static class Builder { private final alfio.model.AdditionalService src; private ZoneId zoneId; - private List additionalServiceFields = new ArrayList<>(); + private final List additionalServiceFields = new ArrayList<>(); private List title = new ArrayList<>(); private List description = new ArrayList<>(); private PriceContainer priceContainer; @@ -448,7 +448,7 @@ public AdditionalServiceText(@JsonProperty("id") Integer id, } public static AdditionalServiceText from(alfio.model.AdditionalServiceText src) { - return new AdditionalServiceText(src.getId(), src.getLocale(), src.getValue(), src.getType()); + return new AdditionalServiceText(src.id(), src.locale(), src.value(), src.type()); } } } diff --git a/src/main/java/alfio/model/modification/GroupMemberModification.java b/src/main/java/alfio/model/modification/GroupMemberModification.java index ee87a00b43..9085ae1a3d 100644 --- a/src/main/java/alfio/model/modification/GroupMemberModification.java +++ b/src/main/java/alfio/model/modification/GroupMemberModification.java @@ -43,12 +43,10 @@ public GroupMemberModification(@JsonProperty("id") Integer id, public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof GroupMemberModification)) { + if (!(o instanceof GroupMemberModification that)) { return false; } - GroupMemberModification that = (GroupMemberModification) o; - return new EqualsBuilder() .append(id, that.id) .append(value, that.value) diff --git a/src/main/java/alfio/model/modification/MetadataModification.java b/src/main/java/alfio/model/modification/MetadataModification.java index e24de54909..1d353821c1 100644 --- a/src/main/java/alfio/model/modification/MetadataModification.java +++ b/src/main/java/alfio/model/modification/MetadataModification.java @@ -48,7 +48,8 @@ public AlfioMetadata toMetadataObj() { return new AlfioMetadata( new OnlineConfiguration(callLinks.stream().map(CallLinkModification::toCallLink).collect(Collectors.toList())), requirementsDescriptions, - List.of() + List.of(), + null ); } diff --git a/src/main/java/alfio/model/modification/OrganizationModification.java b/src/main/java/alfio/model/modification/OrganizationModification.java index b229e46429..cadf98aad7 100644 --- a/src/main/java/alfio/model/modification/OrganizationModification.java +++ b/src/main/java/alfio/model/modification/OrganizationModification.java @@ -17,8 +17,10 @@ package alfio.model.modification; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; +import org.apache.commons.lang3.StringUtils; @Getter public class OrganizationModification { @@ -44,4 +46,12 @@ public OrganizationModification(@JsonProperty("id") Integer id, this.externalId = externalId; this.slug = slug; } + + @JsonIgnore + public boolean isValid(boolean create) { + return (create || (id != null && id > 0)) + && StringUtils.isNotEmpty(name) + && StringUtils.isNotEmpty(email) + && StringUtils.isNotEmpty(description); + } } diff --git a/src/main/java/alfio/model/modification/PollModification.java b/src/main/java/alfio/model/modification/PollModification.java index d94007420e..34c60f00eb 100644 --- a/src/main/java/alfio/model/modification/PollModification.java +++ b/src/main/java/alfio/model/modification/PollModification.java @@ -66,23 +66,23 @@ public boolean isValid(boolean update) { } public static PollModification from(Poll poll) { - return new PollModification(poll.getId(), - poll.getTitle(), - poll.getDescription(), - poll.getOrder(), + return new PollModification(poll.id(), + poll.title(), + poll.description(), + poll.order(), List.of(), - !poll.getAllowedTags().isEmpty(), - poll.getStatus()); + !poll.allowedTags().isEmpty(), + poll.status()); } public static PollModification from(PollWithOptions pollWithOptions) { - var poll = pollWithOptions.getPoll(); - return new PollModification(poll.getId(), - poll.getTitle(), - poll.getDescription(), - poll.getOrder(), - pollWithOptions.getOptions().stream().map(PollOptionModification::from).collect(Collectors.toList()), - !poll.getAllowedTags().isEmpty(), - poll.getStatus()); + var poll = pollWithOptions.poll(); + return new PollModification(poll.id(), + poll.title(), + poll.description(), + poll.order(), + pollWithOptions.options().stream().map(PollOptionModification::from).collect(Collectors.toList()), + !poll.allowedTags().isEmpty(), + poll.status()); } } diff --git a/src/main/java/alfio/model/modification/PollOptionModification.java b/src/main/java/alfio/model/modification/PollOptionModification.java index 7aee8b2762..cbd58eeb43 100644 --- a/src/main/java/alfio/model/modification/PollOptionModification.java +++ b/src/main/java/alfio/model/modification/PollOptionModification.java @@ -45,6 +45,6 @@ public boolean isValid(boolean update) { } public static PollOptionModification from(PollOption option) { - return new PollOptionModification(option.getId(), option.getTitle(), option.getDescription()); + return new PollOptionModification(option.id(), option.title(), option.description()); } } diff --git a/src/main/java/alfio/model/modification/PromoCodeDiscountModification.java b/src/main/java/alfio/model/modification/PromoCodeDiscountModification.java index 9f5c60ca5e..a1e285c7e0 100644 --- a/src/main/java/alfio/model/modification/PromoCodeDiscountModification.java +++ b/src/main/java/alfio/model/modification/PromoCodeDiscountModification.java @@ -36,6 +36,7 @@ public class PromoCodeDiscountModification { private final Integer organizationId; private final Integer eventId; private final String promoCode; + private final String currencyCode; private final DateTimeModification start; private final DateTimeModification end; private final BigDecimal discountAmount; @@ -57,6 +58,7 @@ public PromoCodeDiscountModification( @JsonProperty("start") DateTimeModification start, @JsonProperty("end") DateTimeModification end, @JsonProperty("discountAmount") BigDecimal discountAmount, + @JsonProperty("currencyCode") String currencyCode, @JsonProperty("discountType") DiscountType discountType, @JsonProperty("categories") List categories, @JsonProperty("utcOffset") Integer utcOffset, @@ -72,6 +74,7 @@ public PromoCodeDiscountModification( this.start = start; this.end = end; this.discountAmount = discountAmount; + this.currencyCode = currencyCode; this.discountType = discountType; this.categories = Optional.ofNullable(categories).map(l -> l.stream().filter(Objects::nonNull).collect(Collectors.toList())).orElse(Collections.emptyList()); this.utcOffset = utcOffset; @@ -90,7 +93,7 @@ private int getDiscountInCents(String currencyCode) { return MonetaryUtil.unitToCents(discountAmount, currencyCode); } - public int getDiscountValue(String currencyCode) { + public int getDiscountValue() { if(codeType != PromoCodeDiscount.CodeType.DISCOUNT) { return 0; } diff --git a/src/main/java/alfio/model/modification/PromoCodeDiscountWithFormattedTimeAndAmount.java b/src/main/java/alfio/model/modification/PromoCodeDiscountWithFormattedTimeAndAmount.java index d7d01a47d6..9db6e4f7b5 100644 --- a/src/main/java/alfio/model/modification/PromoCodeDiscountWithFormattedTimeAndAmount.java +++ b/src/main/java/alfio/model/modification/PromoCodeDiscountWithFormattedTimeAndAmount.java @@ -59,8 +59,9 @@ public String getFormattedEnd() { } public String getFormattedDiscountAmount() { - if(promo.getFixedAmount() && StringUtils.isNotBlank(eventCurrency)) { - return MonetaryUtil.formatCents(promo.getDiscountAmount(), eventCurrency); + var currency = StringUtils.firstNonEmpty(eventCurrency, promo.getCurrencyCode()); + if(promo.getFixedAmount() && StringUtils.isNotBlank(currency)) { + return MonetaryUtil.formatCents(promo.getDiscountAmount(), currency); } return null; } diff --git a/src/main/java/alfio/model/modification/ReservationRequest.java b/src/main/java/alfio/model/modification/ReservationRequest.java new file mode 100644 index 0000000000..1ae7610ff5 --- /dev/null +++ b/src/main/java/alfio/model/modification/ReservationRequest.java @@ -0,0 +1,43 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.modification; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static alfio.util.MiscUtils.getAtIndexOrNull; + +public interface ReservationRequest { + Integer getTicketCategoryId(); + Integer getQuantity(); + List> getMetadata(); + + default List getAttendees() { + return metadataToAttendeesList(getQuantity(), getMetadata()); + } + + static List metadataToAttendeesList(Integer quantity, List> metadata) { + int q = Objects.requireNonNullElse(quantity, 0); + return Stream.iterate(0, s -> s+1) + .limit(q) + .map(i -> new AttendeeData(null, null, null, getAtIndexOrNull(metadata, i))) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/alfio/model/modification/SendCodeModification.java b/src/main/java/alfio/model/modification/SendCodeModification.java index a8c10693d7..e402e842ef 100644 --- a/src/main/java/alfio/model/modification/SendCodeModification.java +++ b/src/main/java/alfio/model/modification/SendCodeModification.java @@ -18,11 +18,11 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.EqualsAndHashCode; import lombok.Getter; +import java.util.Objects; + @Getter -@EqualsAndHashCode public class SendCodeModification { private final String code; @@ -41,4 +41,16 @@ public SendCodeModification(@JsonProperty("code") String code, this.language = language; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SendCodeModification that = (SendCodeModification) o; + return Objects.equals(code, that.code) && Objects.equals(assignee, that.assignee) && Objects.equals(email, that.email) && Objects.equals(language, that.language); + } + + @Override + public int hashCode() { + return Objects.hash(code, assignee, email, language); + } } diff --git a/src/main/java/alfio/model/modification/SubscriptionDescriptorModification.java b/src/main/java/alfio/model/modification/SubscriptionDescriptorModification.java index c1c5e56385..f8490df5db 100644 --- a/src/main/java/alfio/model/modification/SubscriptionDescriptorModification.java +++ b/src/main/java/alfio/model/modification/SubscriptionDescriptorModification.java @@ -17,6 +17,8 @@ package alfio.model.modification; import alfio.model.PriceContainer.VatStatus; +import alfio.model.result.ErrorCode; +import alfio.model.result.Result; import alfio.model.subscription.SubscriptionDescriptor; import alfio.model.subscription.SubscriptionDescriptor.SubscriptionTimeUnit; import alfio.model.subscription.SubscriptionDescriptor.SubscriptionUsageType; @@ -33,6 +35,10 @@ import java.util.Map; import java.util.UUID; +import static java.util.Objects.requireNonNullElse; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.length; + @Getter public class SubscriptionDescriptorModification { private final UUID id; @@ -89,8 +95,8 @@ public SubscriptionDescriptorModification(@JsonProperty("id") UUID id, @JsonProperty("timeZone") ZoneId timeZone, @JsonProperty("supportsTicketsGeneration") Boolean supportsTicketsGeneration) { this.id = id; - this.title = title; - this.description = description; + this.title = requireNonNullElse(title, Map.of()); + this.description = requireNonNullElse(description, Map.of()); this.maxAvailable = maxAvailable; this.onSaleFrom = onSaleFrom; this.onSaleTo = onSaleTo; @@ -110,7 +116,7 @@ public SubscriptionDescriptorModification(@JsonProperty("id") UUID id, this.termsAndConditionsUrl = termsAndConditionsUrl; this.privacyPolicyUrl = privacyPolicyUrl; this.fileBlobId = fileBlobId; - this.paymentProxies = paymentProxies; + this.paymentProxies = requireNonNullElse(paymentProxies, List.of()); this.timeZone = timeZone; this.supportsTicketsGeneration = supportsTicketsGeneration; } @@ -167,4 +173,23 @@ public static SubscriptionDescriptorModification fromModel(SubscriptionDescripto subscriptionDescriptor.getZoneId(), subscriptionDescriptor.isSupportsTicketsGeneration()); } + + public static Result validate(SubscriptionDescriptorModification input) { + return new Result.Builder() + .checkPrecondition(() -> !input.title.isEmpty(), ErrorCode.custom("title", "Title is mandatory")) + .checkPrecondition(() -> !input.description.isEmpty(), ErrorCode.custom("description", "Description is mandatory")) + .checkPrecondition(() -> input.title.keySet().equals(input.description.keySet()), ErrorCode.custom("locale-mismatch", "Mismatch between supported translations")) + .checkPrecondition(() -> isNotBlank(input.termsAndConditionsUrl), ErrorCode.custom("terms", "Terms and Conditions are mandatory")) + .checkPrecondition(() -> isNotBlank(input.fileBlobId), ErrorCode.custom("logo", "Logo is required")) + .checkPrecondition(() -> isNotBlank(input.currency) && length(input.currency) == 3, ErrorCode.custom("currency", "Currency Code is required")) + .checkPrecondition(() -> input.vatStatus != null, ErrorCode.custom("taxPolicy", "Tax Policy is required")) + .checkPrecondition(() -> input.vat != null, ErrorCode.custom("taxes", "Tax percentage is required")) + .checkPrecondition(() -> input.onSaleFrom != null, ErrorCode.custom("onSaleFrom", "'On Sale From' is required")) + .checkPrecondition(() -> input.timeZone != null, ErrorCode.custom("timeZone", "Time Zone is required")) + .checkPrecondition(() -> !input.paymentProxies.isEmpty(), ErrorCode.custom("paymentMethods", "At least one Payment Method is required")) + .checkPrecondition(() -> input.price != null, ErrorCode.custom("price", "Price is mandatory")) + .checkPrecondition(() -> input.usageType != null, ErrorCode.custom("usageType", "UsageType is mandatory")) + .checkPrecondition(() -> isNotBlank(input.fileBlobId), ErrorCode.custom("logo", "Logo is required")) + .build(() -> input); + } } diff --git a/src/main/java/alfio/model/modification/TicketFieldDescriptionModification.java b/src/main/java/alfio/model/modification/TicketFieldDescriptionModification.java index 11d126931a..cf89975f60 100644 --- a/src/main/java/alfio/model/modification/TicketFieldDescriptionModification.java +++ b/src/main/java/alfio/model/modification/TicketFieldDescriptionModification.java @@ -16,17 +16,28 @@ */ package alfio.model.modification; - -import lombok.Getter; -import lombok.Setter; - import java.util.Map; -@Getter -@Setter + public class TicketFieldDescriptionModification { private int ticketFieldConfigurationId; private String locale; private Map description; + + public int getTicketFieldConfigurationId() { + return ticketFieldConfigurationId; + } + + public void setTicketFieldConfigurationId(int ticketFieldConfigurationId) { + this.ticketFieldConfigurationId = ticketFieldConfigurationId; + } + + public String getLocale() { + return locale; + } + + public Map getDescription() { + return description; + } } diff --git a/src/main/java/alfio/model/modification/TicketReservationModification.java b/src/main/java/alfio/model/modification/TicketReservationModification.java index ff2afdf08e..e09698b444 100644 --- a/src/main/java/alfio/model/modification/TicketReservationModification.java +++ b/src/main/java/alfio/model/modification/TicketReservationModification.java @@ -23,7 +23,7 @@ import java.util.Map; @Data -public class TicketReservationModification implements Serializable { +public class TicketReservationModification implements ReservationRequest, Serializable { private Integer ticketCategoryId; private Integer quantity; private List> metadata; diff --git a/src/main/java/alfio/model/modification/TicketReservationWithOptionalCodeModification.java b/src/main/java/alfio/model/modification/TicketReservationWithOptionalCodeModification.java index c1a220f094..91b035d076 100644 --- a/src/main/java/alfio/model/modification/TicketReservationWithOptionalCodeModification.java +++ b/src/main/java/alfio/model/modification/TicketReservationWithOptionalCodeModification.java @@ -25,6 +25,6 @@ @Data public class TicketReservationWithOptionalCodeModification { @Delegate - private final TicketReservationModification ticketReservationModification; + private final ReservationRequest ticketReservationModification; private final Optional specialPrice; } diff --git a/src/main/java/alfio/model/modification/TransactionMetadataModification.java b/src/main/java/alfio/model/modification/TransactionMetadataModification.java new file mode 100644 index 0000000000..09fcd23b2d --- /dev/null +++ b/src/main/java/alfio/model/modification/TransactionMetadataModification.java @@ -0,0 +1,40 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.modification; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TransactionMetadataModification { + private final DateTimeModification timestamp; + private final String notes; + + @JsonCreator + public TransactionMetadataModification(@JsonProperty("timestamp") DateTimeModification timestamp, + @JsonProperty("notes") String notes) { + this.timestamp = timestamp; + this.notes = notes; + } + + public DateTimeModification getTimestamp() { + return timestamp; + } + + public String getNotes() { + return notes; + } +} diff --git a/src/main/java/alfio/model/modification/UploadBase64FileModification.java b/src/main/java/alfio/model/modification/UploadBase64FileModification.java index 75f5654e69..b34df4c0db 100644 --- a/src/main/java/alfio/model/modification/UploadBase64FileModification.java +++ b/src/main/java/alfio/model/modification/UploadBase64FileModification.java @@ -16,15 +16,13 @@ */ package alfio.model.modification; -import lombok.Data; - import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -@Data + public class UploadBase64FileModification { private byte[] file; @@ -33,6 +31,38 @@ public class UploadBase64FileModification { private String name; private Map attributes; + public void setFile(byte[] file) { + this.file = file; + } + + public void setFileAsString(String fileAsString) { + this.fileAsString = fileAsString; + } + + public String getFileAsString() { + return fileAsString; + } + + public void setType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + public InputStream getInputStream() { return new ByteArrayInputStream(file); } diff --git a/src/main/java/alfio/model/modification/support/LocationDescriptor.java b/src/main/java/alfio/model/modification/support/LocationDescriptor.java index ed9d0b65ab..a00007d16b 100644 --- a/src/main/java/alfio/model/modification/support/LocationDescriptor.java +++ b/src/main/java/alfio/model/modification/support/LocationDescriptor.java @@ -21,18 +21,15 @@ import alfio.model.system.ConfigurationKeys; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.EqualsAndHashCode; -import lombok.Getter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.text.StringSubstitutor; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.TimeZone; -@Getter -@EqualsAndHashCode public class LocationDescriptor { @@ -91,11 +88,13 @@ public static ConfigurationKeys.GeoInfoProvider getProvider(Map + "https://maps.googleapis.com/maps/api/staticmap?center=${latitude},${longitude}&key=${key}&zoom=16&size=400x400&markers=color:blue%7Clabel:E%7C${latitude},${longitude}"; + case HERE -> + "https://image.maps.ls.hereapi.com/mia/1.6/mapview?c=${latitude},${longitude}&z=16&w=400&h=400&poi=${latitude},${longitude}&apikey=${key}"; + default -> ""; + }; } private static void fillParams(ConfigurationKeys.GeoInfoProvider provider, Map geoConf, Map params) { @@ -106,4 +105,31 @@ private static void fillParams(ConfigurationKeys.GeoInfoProvider provider, Map title, + @Column("description") @JSONData Map description, + @Column("allowed_tags") @Array List allowedTags, + @Column("poll_order") int order, + @Column("event_id_fk") int eventId, + @Column("organization_id_fk") int organizationId) { public enum PollStatus { @@ -36,33 +40,17 @@ public enum PollStatus { CLOSED } - private final long id; - private final PollStatus status; - private final Map title; - private final Map description; - private final List allowedTags; - private final int order; - private final int eventId; - private final int organizationId; - - public Poll(@Column("id") long id, - @Column("status") PollStatus status, - @Column("title") @JSONData Map title, - @Column("description") @JSONData Map description, - @Column("allowed_tags") @Array List allowedTags, - @Column("poll_order") int order, - @Column("event_id_fk") int eventId, - @Column("organization_id_fk") int organizationId) { - - this.id = id; - this.status = status; - this.title = title; - this.description = description; - this.allowedTags = allowedTags; - this.order = order; - this.eventId = eventId; - this.organizationId = organizationId; + @Override + public String toString() { + return new ToStringBuilder(this) + .append("id", id) + .append("status", status) + .append("title", title) + .append("description", description) + .append("allowedTags", allowedTags) + .append("order", order) + .append("eventId", eventId) + .append("organizationId", organizationId) + .toString(); } - - } diff --git a/src/main/java/alfio/model/poll/PollOption.java b/src/main/java/alfio/model/poll/PollOption.java index 092989b0b1..575bdf6301 100644 --- a/src/main/java/alfio/model/poll/PollOption.java +++ b/src/main/java/alfio/model/poll/PollOption.java @@ -18,24 +18,12 @@ import alfio.model.support.JSONData; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; import java.util.Map; -@Getter -public class PollOption { - private final Long id; - private final Long pollId; - private final Map title; - private final Map description; - public PollOption(@Column("id") Long id, - @Column("poll_id_fk") Long pollId, - @Column("title") @JSONData Map title, - @Column("description") @JSONData Map description) { - this.id = id; - this.pollId = pollId; - this.title = title; - this.description = description; - } +public record PollOption(@Column("id") Long id, + @Column("poll_id_fk") Long pollId, + @Column("title") @JSONData Map title, + @Column("description") @JSONData Map description) { } diff --git a/src/main/java/alfio/model/poll/PollOptionStatistics.java b/src/main/java/alfio/model/poll/PollOptionStatistics.java index b8634336d4..60ab5b18a7 100644 --- a/src/main/java/alfio/model/poll/PollOptionStatistics.java +++ b/src/main/java/alfio/model/poll/PollOptionStatistics.java @@ -17,17 +17,7 @@ package alfio.model.poll; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class PollOptionStatistics { - - private final int votes; - private final long optionId; - - public PollOptionStatistics(@Column("votes") int votes, - @Column("poll_option_id_fk") long optionId) { - this.votes = votes; - this.optionId = optionId; - } +public record PollOptionStatistics(@Column("votes") int votes, + @Column("poll_option_id_fk") long optionId) { } diff --git a/src/main/java/alfio/model/poll/PollParticipant.java b/src/main/java/alfio/model/poll/PollParticipant.java index 6fc8b8cb09..ad132c8c75 100644 --- a/src/main/java/alfio/model/poll/PollParticipant.java +++ b/src/main/java/alfio/model/poll/PollParticipant.java @@ -17,27 +17,11 @@ package alfio.model.poll; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class PollParticipant { +public record PollParticipant(@Column("t_id") int id, + @Column("t_first_name") String firstName, + @Column("t_last_name") String lastName, + @Column("t_email_address") String emailAddress, + @Column("tc_name") String categoryName) { - private final int id; - private final String firstName; - private final String lastName; - private final String emailAddress; - private final String categoryName; - - - public PollParticipant(@Column("t_id") int id, - @Column("t_first_name") String firstName, - @Column("t_last_name") String lastName, - @Column("t_email_address") String emailAddress, - @Column("tc_name") String categoryName) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - this.emailAddress = emailAddress; - this.categoryName = categoryName; - } } diff --git a/src/main/java/alfio/model/poll/PollStatistics.java b/src/main/java/alfio/model/poll/PollStatistics.java index f367092aa7..efdee35bba 100644 --- a/src/main/java/alfio/model/poll/PollStatistics.java +++ b/src/main/java/alfio/model/poll/PollStatistics.java @@ -17,19 +17,23 @@ package alfio.model.poll; import alfio.util.MonetaryUtil; -import lombok.AllArgsConstructor; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; import java.util.stream.Collectors; -@AllArgsConstructor public class PollStatistics { private final int totalVotes; private final int allowedParticipants; private final List countByOption; + public PollStatistics(int totalVotes, int allowedParticipants, List countByOption) { + this.totalVotes = totalVotes; + this.allowedParticipants = allowedParticipants; + this.countByOption = countByOption; + } + public int getTotalVotes() { return totalVotes; } @@ -46,8 +50,8 @@ public List getOptionStatistics() { BigDecimal totalVotes = new BigDecimal(this.totalVotes); return countByOption.stream() .map(o -> { - var percentage = getVotesPercentage(totalVotes, o.getVotes()); - return new StatisticDetail(o.getVotes(), o.getOptionId(), percentage); + var percentage = getVotesPercentage(totalVotes, o.votes()); + return new StatisticDetail(o.votes(), o.optionId(), percentage); }) .collect(Collectors.toList()); } diff --git a/src/main/java/alfio/model/poll/PollWithOptions.java b/src/main/java/alfio/model/poll/PollWithOptions.java index cc23b23185..d220df4919 100644 --- a/src/main/java/alfio/model/poll/PollWithOptions.java +++ b/src/main/java/alfio/model/poll/PollWithOptions.java @@ -18,20 +18,5 @@ import java.util.List; -public class PollWithOptions { - private final Poll poll; - private final List options; - - public PollWithOptions(Poll poll, List options) { - this.poll = poll; - this.options = options; - } - - public List getOptions() { - return options; - } - - public Poll getPoll() { - return poll; - } +public record PollWithOptions(Poll poll, List options) { } diff --git a/src/main/java/alfio/model/result/ErrorCode.java b/src/main/java/alfio/model/result/ErrorCode.java index 574e663719..ce36ca414c 100644 --- a/src/main/java/alfio/model/result/ErrorCode.java +++ b/src/main/java/alfio/model/result/ErrorCode.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Getter; -import lombok.RequiredArgsConstructor; import java.util.function.Supplier; @@ -35,7 +34,7 @@ default String getLocation() { String getDescription(); Object[] getArguments(); - @RequiredArgsConstructor + @Getter enum CategoryError implements ErrorCode { NOT_FOUND("not_found", "Category not found"), @@ -47,6 +46,11 @@ enum CategoryError implements ErrorCode { private final String code; private final String description; + CategoryError(String code, String description) { + this.code = code; + this.description = description; + } + @Override public String toString() { @@ -59,7 +63,7 @@ public Object[] getArguments() { } } - @RequiredArgsConstructor + @Getter enum EventError implements ErrorCode { NOT_FOUND("not_found", "No event has been found"), @@ -68,6 +72,11 @@ enum EventError implements ErrorCode { private final String code; private final String description; + EventError(String code, String description) { + this.code = code; + this.description = description; + } + @Override public String toString() { @@ -80,7 +89,6 @@ public Object[] getArguments() { } } - @RequiredArgsConstructor @Getter enum ReservationError implements ErrorCode { NOT_FOUND("not_found", "No reservation has been found"), @@ -90,6 +98,11 @@ enum ReservationError implements ErrorCode { private final String code; private final String description; + ReservationError(String code, String description) { + this.code = code; + this.description = description; + } + @Override public String toString() { diff --git a/src/main/java/alfio/model/result/Result.java b/src/main/java/alfio/model/result/Result.java index 92def651ab..83b8352802 100644 --- a/src/main/java/alfio/model/result/Result.java +++ b/src/main/java/alfio/model/result/Result.java @@ -17,7 +17,6 @@ package alfio.model.result; import alfio.model.result.ValidationResult.ErrorDescriptor; -import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.tuple.Pair; @@ -29,7 +28,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; -@AllArgsConstructor + @Getter public class Result { @@ -37,6 +36,12 @@ public class Result { private final T data; private final List errors; + public Result(ResultStatus status, T data, List errors) { + this.status = status; + this.data = data; + this.errors = errors; + } + public static Result success(T data) { return new Result<>(ResultStatus.OK, data, Collections.emptyList()); } @@ -84,6 +89,14 @@ public ErrorCode getFirstErrorOrNull() { return errors.get(0); } + public String getFormattedErrors() { + if(isSuccess()) { + return null; + } + return getErrors().stream().map(ErrorCode::getDescription) + .collect(Collectors.joining("\n")); + } + public enum ResultStatus { OK, VALIDATION_ERROR, ERROR } diff --git a/src/main/java/alfio/model/result/ValidationResult.java b/src/main/java/alfio/model/result/ValidationResult.java index a757fd432a..eed5cf115b 100644 --- a/src/main/java/alfio/model/result/ValidationResult.java +++ b/src/main/java/alfio/model/result/ValidationResult.java @@ -17,7 +17,7 @@ package alfio.model.result; import lombok.Getter; -import lombok.ToString; +import org.apache.commons.lang3.builder.ToStringBuilder; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; @@ -88,7 +88,6 @@ public boolean isSuccess() { return errorCount == 0; } - @ToString @Getter public static final class ErrorDescriptor implements ErrorCode { private final String fieldName; @@ -138,6 +137,16 @@ public static ErrorDescriptor fromFieldError(FieldError fieldError) { public static ErrorDescriptor fromObjectError(ObjectError objectError) { return new ErrorDescriptor("", objectError.getObjectName(), objectError.getCode(), objectError.getArguments()); } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("fieldName", fieldName) + .append("message", message) + .append("code", code) + .append("arguments", arguments) + .toString(); + } } @FunctionalInterface diff --git a/src/main/java/alfio/model/subscription/Subscription.java b/src/main/java/alfio/model/subscription/Subscription.java index f31bb44621..5e3cd3eb26 100644 --- a/src/main/java/alfio/model/subscription/Subscription.java +++ b/src/main/java/alfio/model/subscription/Subscription.java @@ -91,11 +91,11 @@ public Subscription(@Column("id") UUID id, this.currency = currency; this.status = status; this.maxEntries = maxEntries; - var zoneId = ZoneId.of(timeZone); - this.zoneId = zoneId; - this.validityFrom = atZone(validityFrom, zoneId); - this.validityTo = atZone(validityTo, zoneId); - this.confirmationTimestamp = atZone(confirmationTimestamp, zoneId); + var zone = ZoneId.of(timeZone); + this.zoneId = zone; + this.validityFrom = atZone(validityFrom, zone); + this.validityTo = atZone(validityTo, zone); + this.confirmationTimestamp = atZone(confirmationTimestamp, zone); } public boolean isValid(Optional bindingResult) { diff --git a/src/main/java/alfio/model/subscription/SubscriptionPriceContainer.java b/src/main/java/alfio/model/subscription/SubscriptionPriceContainer.java index c693056806..fa8752b001 100644 --- a/src/main/java/alfio/model/subscription/SubscriptionPriceContainer.java +++ b/src/main/java/alfio/model/subscription/SubscriptionPriceContainer.java @@ -18,7 +18,6 @@ import alfio.model.PriceContainer; import alfio.model.PromoCodeDiscount; -import lombok.AllArgsConstructor; import java.math.BigDecimal; import java.util.Optional; @@ -26,13 +25,18 @@ import static alfio.util.MonetaryUtil.centsToUnit; import static alfio.util.MonetaryUtil.unitToCents; -@AllArgsConstructor public class SubscriptionPriceContainer implements PriceContainer { private final Subscription subscription; private final PromoCodeDiscount promoCodeDiscount; private final SubscriptionDescriptor descriptor; + public SubscriptionPriceContainer(Subscription subscription, PromoCodeDiscount promoCodeDiscount, SubscriptionDescriptor descriptor) { + this.subscription = subscription; + this.promoCodeDiscount = promoCodeDiscount; + this.descriptor = descriptor; + } + @Override public int getSrcPriceCts() { diff --git a/src/main/java/alfio/model/subscription/SubscriptionWithUsageDetails.java b/src/main/java/alfio/model/subscription/SubscriptionWithUsageDetails.java index 383dfc1185..6a9b5aa19a 100644 --- a/src/main/java/alfio/model/subscription/SubscriptionWithUsageDetails.java +++ b/src/main/java/alfio/model/subscription/SubscriptionWithUsageDetails.java @@ -18,14 +18,21 @@ import alfio.model.TicketReservationWithEventIdentifier; import lombok.Getter; -import lombok.RequiredArgsConstructor; import java.util.List; -@RequiredArgsConstructor + @Getter public class SubscriptionWithUsageDetails { private final Subscription subscription; private final UsageDetails usageDetails; private final List reservations; + + public SubscriptionWithUsageDetails(Subscription subscription, + UsageDetails usageDetails, + List reservations) { + this.subscription = subscription; + this.usageDetails = usageDetails; + this.reservations = reservations; + } } diff --git a/src/main/java/alfio/model/subscription/UsageDetails.java b/src/main/java/alfio/model/subscription/UsageDetails.java index 8a9e6f8280..1329bf3682 100644 --- a/src/main/java/alfio/model/subscription/UsageDetails.java +++ b/src/main/java/alfio/model/subscription/UsageDetails.java @@ -16,16 +16,20 @@ */ package alfio.model.subscription; -import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor @Getter public class UsageDetails { private final Integer total; private final Integer used; private final Integer available; + public UsageDetails(Integer total, Integer used, Integer available) { + this.total = total; + this.used = used; + this.available = available; + } + public static UsageDetails fromSubscription(Subscription subscription, int usageCount) { int maxEntries = Math.max(subscription.getMaxEntries(), 0); return new UsageDetails(maxEntries == 0 ? null : maxEntries, diff --git a/src/main/java/alfio/model/support/EventBasicInfo.java b/src/main/java/alfio/model/support/EventBasicInfo.java new file mode 100644 index 0000000000..0d1947dc0b --- /dev/null +++ b/src/main/java/alfio/model/support/EventBasicInfo.java @@ -0,0 +1,44 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.support; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class EventBasicInfo { + private final String shortName; + private final String displayName; + + @JsonCreator + public EventBasicInfo(@JsonProperty("shortName") String shortName, + @JsonProperty("displayName") String displayName) { + this.shortName = shortName; + this.displayName = displayName; + } + + public String getShortName() { + return shortName; + } + + public String getDisplayName() { + return displayName; + } + + public String getPublicIdentifier() { + return getShortName(); + } +} diff --git a/src/main/java/alfio/model/support/ReservationInfo.java b/src/main/java/alfio/model/support/ReservationInfo.java new file mode 100644 index 0000000000..ed6e2671a6 --- /dev/null +++ b/src/main/java/alfio/model/support/ReservationInfo.java @@ -0,0 +1,142 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.support; + +import alfio.model.PriceContainer; +import alfio.model.transaction.PaymentProxy; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class ReservationInfo { + private final String id; + private final String invoiceNumber; + private final String firstName; + private final String lastName; + private final String companyName; + private final String taxId; + private final String email; + private final PaymentProxy paymentType; + private final Integer finalPriceCts; + private final Integer srcPriceCts; + private final Integer taxCts; + private final PriceContainer.VatStatus taxStatus; + private final String taxCode; + private final String currency; + private final String confirmationTimestamp; + private final List tickets; + + @JsonCreator + ReservationInfo(@JsonProperty("id") String id, + @JsonProperty("invoiceNumber") String invoiceNumber, + @JsonProperty("firstName") String firstName, + @JsonProperty("lastName") String lastName, + @JsonProperty("companyName") String companyName, + @JsonProperty("taxId") String taxId, + @JsonProperty("email") String email, + @JsonProperty("paymentType") PaymentProxy paymentType, + @JsonProperty("finalPriceCts") Integer finalPriceCts, + @JsonProperty("srcPriceCts") Integer srcPriceCts, + @JsonProperty("taxCts") Integer taxCts, + @JsonProperty("taxStatus") PriceContainer.VatStatus taxStatus, + @JsonProperty("taxCode") String taxCode, + @JsonProperty("currency") String currency, + @JsonProperty("confirmationTimestamp") String confirmationTimestamp, + @JsonProperty("tickets") List tickets) { + this.id = id; + this.invoiceNumber = invoiceNumber; + this.firstName = firstName; + this.lastName = lastName; + this.companyName = companyName; + this.taxId = taxId; + this.email = email; + this.paymentType = paymentType; + this.finalPriceCts = finalPriceCts; + this.srcPriceCts = srcPriceCts; + this.taxCts = taxCts; + this.taxStatus = taxStatus; + this.taxCode = taxCode; + this.currency = currency; + this.confirmationTimestamp = confirmationTimestamp; + this.tickets = tickets; + } + + public String getId() { + return id; + } + + public String getInvoiceNumber() { + return invoiceNumber; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public PaymentProxy getPaymentType() { + return paymentType; + } + + public String getCurrency() { + return currency; + } + + public String getConfirmationTimestamp() { + return confirmationTimestamp; + } + + public List getTickets() { + return tickets; + } + + public Integer getFinalPriceCts() { + return finalPriceCts; + } + + public Integer getSrcPriceCts() { + return srcPriceCts; + } + + public PriceContainer.VatStatus getTaxStatus() { + return taxStatus; + } + + public String getTaxCode() { + return taxCode; + } + + public String getCompanyName() { + return companyName; + } + + public String getTaxId() { + return taxId; + } + + public Integer getTaxCts() { + return taxCts; + } +} diff --git a/src/main/java/alfio/model/support/TicketInfo.java b/src/main/java/alfio/model/support/TicketInfo.java new file mode 100644 index 0000000000..38f67139d2 --- /dev/null +++ b/src/main/java/alfio/model/support/TicketInfo.java @@ -0,0 +1,90 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.support; + +import alfio.model.PriceContainer; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TicketInfo { + private final String id; + private final String firstName; + private final String lastName; + private final String type; + private final String status; + private final Integer finalPriceCts; + private final Integer srcPriceCts; + private final Integer taxCts; + private final PriceContainer.VatStatus taxStatus; + + @JsonCreator + private TicketInfo(@JsonProperty("id") String id, + @JsonProperty("firstName") String firstName, + @JsonProperty("lastName") String lastName, + @JsonProperty("type") String type, + @JsonProperty("status") String status, + @JsonProperty("finalPriceCts") Integer finalPriceCts, + @JsonProperty("srcPriceCts") Integer srcPriceCts, + @JsonProperty("taxCts") Integer taxCts, + @JsonProperty("taxStatus") PriceContainer.VatStatus taxStatus) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.type = type; + this.status = status; + this.finalPriceCts = finalPriceCts; + this.srcPriceCts = srcPriceCts; + this.taxCts = taxCts; + this.taxStatus = taxStatus; + } + + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getType() { + return type; + } + + public String getStatus() { + return status; + } + + public Integer getFinalPriceCts() { + return finalPriceCts; + } + + public Integer getSrcPriceCts() { + return srcPriceCts; + } + + public Integer getTaxCts() { + return taxCts; + } + + public PriceContainer.VatStatus getTaxStatus() { + return taxStatus; + } +} diff --git a/src/main/java/alfio/model/support/TicketWithAdditionalFields.java b/src/main/java/alfio/model/support/TicketWithAdditionalFields.java index 450c2279be..1586404f17 100644 --- a/src/main/java/alfio/model/support/TicketWithAdditionalFields.java +++ b/src/main/java/alfio/model/support/TicketWithAdditionalFields.java @@ -20,7 +20,6 @@ import alfio.model.Ticket; import alfio.model.TicketFieldConfigurationDescriptionAndValue; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; import lombok.experimental.Delegate; import org.apache.commons.lang3.tuple.Pair; @@ -28,7 +27,6 @@ import java.util.Map; import java.util.stream.Collectors; -@AllArgsConstructor public class TicketWithAdditionalFields { @Delegate(excludes = EventAndOrganizationId.class) @JsonIgnore @@ -36,6 +34,12 @@ public class TicketWithAdditionalFields { @JsonIgnore private final List additionalFieldsDescriptionsAndValues; + public TicketWithAdditionalFields(Ticket ticket, + List additionalFieldsDescriptionsAndValues) { + this.ticket = ticket; + this.additionalFieldsDescriptionsAndValues = additionalFieldsDescriptionsAndValues; + } + public Map getAdditionalFields() { return additionalFieldsDescriptionsAndValues.stream() .map(af -> Pair.of(af.getLabelDescription(), af.getValueDescription())) diff --git a/src/main/java/alfio/model/system/Configuration.java b/src/main/java/alfio/model/system/Configuration.java index 5414b8624c..887c667187 100644 --- a/src/main/java/alfio/model/system/Configuration.java +++ b/src/main/java/alfio/model/system/Configuration.java @@ -18,12 +18,14 @@ import alfio.model.EventAndOrganizationId; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.EqualsAndHashCode; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import java.util.Objects; import java.util.function.Function; @Getter @@ -39,10 +41,11 @@ public class Configuration implements Comparable { private final boolean internal; - public Configuration(@Column("id") int id, - @Column("c_key") String key, - @Column("c_value") String value, - @Column("configuration_path_level") ConfigurationPathLevel configurationPathLevel) { + @JsonCreator + public Configuration(@JsonProperty("id") @Column("id") int id, + @JsonProperty("key") @Column("c_key") String key, + @JsonProperty("value") @Column("c_value") String value, + @JsonProperty("configurationPathLevel") @Column("configuration_path_level") ConfigurationPathLevel configurationPathLevel) { this.id = id; this.key = key; this.value = value; @@ -70,10 +73,9 @@ public boolean equals(Object obj) { if (obj == this) { return true; } - if (!(obj instanceof Configuration)) { + if (!(obj instanceof Configuration o)) { return false; } - Configuration o = (Configuration) obj; return new EqualsBuilder().append(configurationKey, o.configurationKey).append(configurationPathLevel, configurationPathLevel).isEquals(); } @@ -87,7 +89,6 @@ public interface ConfigurationPath { ConfigurationPathLevel pathLevel(); } - @EqualsAndHashCode public static class SystemConfigurationPath implements ConfigurationPath { @Override public ConfigurationPathLevel pathLevel() { @@ -96,7 +97,7 @@ public ConfigurationPathLevel pathLevel() { } - @EqualsAndHashCode + @Getter public static class OrganizationConfigurationPath implements ConfigurationPath { @@ -111,9 +112,20 @@ public ConfigurationPathLevel pathLevel() { return ConfigurationPathLevel.ORGANIZATION; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OrganizationConfigurationPath that = (OrganizationConfigurationPath) o; + return id == that.id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } - @EqualsAndHashCode @Getter public static class EventConfigurationPath implements ConfigurationPath { @@ -131,9 +143,20 @@ public ConfigurationPathLevel pathLevel() { return ConfigurationPathLevel.EVENT; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EventConfigurationPath that = (EventConfigurationPath) o; + return organizationId == that.organizationId && id == that.id; + } + + @Override + public int hashCode() { + return Objects.hash(organizationId, id); + } } - @EqualsAndHashCode @Getter public static class TicketCategoryConfigurationPath implements ConfigurationPath { @@ -152,6 +175,18 @@ public ConfigurationPathLevel pathLevel() { return ConfigurationPathLevel.TICKET_CATEGORY; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TicketCategoryConfigurationPath that = (TicketCategoryConfigurationPath) o; + return organizationId == that.organizationId && eventId == that.eventId && id == that.id; + } + + @Override + public int hashCode() { + return Objects.hash(organizationId, eventId, id); + } } public static ConfigurationPath system() { @@ -169,7 +204,6 @@ private static ConfigurationPath ticketCategory(int organizationId, int eventId, // @Getter - @EqualsAndHashCode public static class ConfigurationPathKey { private final ConfigurationPath path; private final ConfigurationKeys key; @@ -178,6 +212,19 @@ private ConfigurationPathKey(ConfigurationPath path, ConfigurationKeys key) { this.path = path; this.key = key; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConfigurationPathKey that = (ConfigurationPathKey) o; + return Objects.equals(path, that.path) && key == that.key; + } + + @Override + public int hashCode() { + return Objects.hash(path, key); + } } // diff --git a/src/main/java/alfio/model/system/ConfigurationKeys.java b/src/main/java/alfio/model/system/ConfigurationKeys.java index 9327b1c0b3..40a9098593 100644 --- a/src/main/java/alfio/model/system/ConfigurationKeys.java +++ b/src/main/java/alfio/model/system/ConfigurationKeys.java @@ -35,6 +35,7 @@ public enum ConfigurationKeys { NOT_RECOGNIZED("option not recognized", true, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.noneOf(ConfigurationPathLevel.class)), INIT_COMPLETED("init succeeded", true, SettingCategory.GENERAL, ComponentType.BOOLEAN, false, EnumSet.noneOf(ConfigurationPathLevel.class), BooleanUtils.FALSE), + SYSTEM_API_KEY("System API Key", true, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.noneOf(ConfigurationPathLevel.class)), SHOW_PROJECT_BANNER("project banner dismissed", true, SettingCategory.GENERAL, ComponentType.BOOLEAN, false, EnumSet.noneOf(ConfigurationPathLevel.class), BooleanUtils.TRUE), @Deprecated SUPPORTED_LANGUAGES("supported languages", true, SettingCategory.GENERAL, ComponentType.LIST, false, EnumSet.of(SYSTEM)), @@ -42,6 +43,7 @@ public enum ConfigurationKeys { BASE_URL("Base application url", false, SettingCategory.GENERAL, ComponentType.TEXT, true, EnumSet.of(SYSTEM)), GLOBAL_PRIVACY_POLICY("Global Privacy Policy URL (to be displayed on the event list)", false, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), GLOBAL_TERMS("Global Terms And Conditions (to be displayed on the event list)", false, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), + ANNOUNCEMENT_BANNER_CONTENT("Announcement banner content", false, SettingCategory.GENERAL, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM)), MAPS_PROVIDER("Select the maps provider (None, Google, Here)", false, SettingCategory.MAP, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), MAPS_CLIENT_API_KEY("Google maps' client api key", false, SettingCategory.MAP, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), @@ -120,9 +122,12 @@ public enum ConfigurationKeys { MAX_EMAIL_PER_CYCLE("How many e-mail should be managed within 5 sec.", false, SettingCategory.MAIL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), MAIL_REPLY_TO("Reply-to address", false, SettingCategory.MAIL, ComponentType.TEXT, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), + MAIL_SET_ORG_REPLY_TO("Set organizer email as reply-to (default: false)", false, SettingCategory.MAIL, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM), "false"), MAIL_SYSTEM_NOTIFICATION_CC("Add additional CC when the system send notifications to the event organizer, can insert multiple email (comma separated)", false, SettingCategory.MAIL, ComponentType.TEXT, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), + MAIL_FOOTER("Email footer", false, SettingCategory.MAIL, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), + //smtp configuration related keys SMTP_HOST("SMTP hostname", false, SettingCategory.MAIL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), SMTP_PORT("SMTP port", false, SettingCategory.MAIL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), @@ -134,6 +139,7 @@ public enum ConfigurationKeys { BANK_TRANSFER_ENABLED("Bank transfer enabled", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION), BooleanUtils.FALSE), DEFERRED_BANK_TRANSFER_ENABLED("Send payment instructions manually (default false)", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), + SHOW_ONLY_BASIC_INSTRUCTIONS("Display only basic payment instructions (default false)", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL("Send payment confirmation email (default true)", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.TRUE), OFFLINE_PAYMENT_DAYS("Maximum number of days allowed to pay an offline ticket", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.TEXT, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), OFFLINE_REMINDER_HOURS("How many hours before expiration should be sent a reminder e-mail for offline payments?", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.TEXT, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), @@ -212,7 +218,8 @@ public enum ConfigurationKeys { VAT_NUMBER_IS_REQUIRED("VAT/GST Number is required for Business Customers (default: false)", false, SettingCategory.INVOICE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), GENERATE_ONLY_INVOICE("Always generate an invoice for paid reservations (default: false)", false, SettingCategory.INVOICE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE("Reuse invoice number as Credit Note number (default: true)", false, SettingCategory.INVOICE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION), BooleanUtils.TRUE), - ENABLE_ITALY_E_INVOICING("Enable the support for italian e-invoicing", false, SettingCategory.INVOICE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), + ENABLE_ITALY_E_INVOICING("Enable the support for italian e-invoicing (default: false)", false, SettingCategory.INVOICE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), + ITALY_E_INVOICING_SEND_PROFORMA("Italian e-invoicing: send proforma invoice (default: false)", false, SettingCategory.INVOICE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.FALSE), ENABLE_EU_VAT_DIRECTIVE("Enable VAT Reverse Charge (default: false)", false, SettingCategory.INVOICE_EU, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION), BooleanUtils.FALSE), ENABLE_REVERSE_CHARGE_ONLINE("Enable VAT Reverse Charge for online tickets (if set overrides global reverse charge, default: true)", false, SettingCategory.INVOICE_EU, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION), BooleanUtils.TRUE), ENABLE_REVERSE_CHARGE_IN_PERSON("Enable VAT Reverse Charge for in-person tickets (if set overrides global reverse charge, default: true)", false, SettingCategory.INVOICE_EU, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION), BooleanUtils.TRUE), @@ -222,17 +229,23 @@ public enum ConfigurationKeys { EU_COUNTRIES_LIST("EU Countries", true, SettingCategory.INVOICE_EU, ComponentType.LIST, false, EnumSet.of(SYSTEM)), @Deprecated EU_VAT_API_ADDRESS("EU VAT API address", true, SettingCategory.INVOICE_EU, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), + APPLY_TAX_TO_CATEGORY("Apply taxes to this Category (default: true)", false, SettingCategory.GENERAL, ComponentType.BOOLEAN, false, EnumSet.of(TICKET_CATEGORY), BooleanUtils.TRUE), // //PASSBOOK - ENABLE_PASS("Enable Apple(tm) Wallet integration", false, SettingCategory.PASS_INTEGRATION, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM), BooleanUtils.FALSE), + ENABLE_PASS("Enable Apple(tm) Wallet integration (default: false)", false, SettingCategory.PASS_INTEGRATION, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM), BooleanUtils.FALSE), PASSBOOK_TYPE_IDENTIFIER("Passbook type identifier", false, SettingCategory.PASS_INTEGRATION, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), PASSBOOK_TEAM_IDENTIFIER("Passbook team identifier", false, SettingCategory.PASS_INTEGRATION, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), PASSBOOK_KEYSTORE("Passbook keystore(base64 encoded keystore)", false, SettingCategory.PASS_INTEGRATION, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM)), PASSBOOK_KEYSTORE_PASSWORD("Passbook keystore password", false, SettingCategory.PASS_INTEGRATION, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), PASSBOOK_PRIVATE_KEY_ALIAS("Passbook Private Key alias", false, SettingCategory.PASS_INTEGRATION, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), + //WALLET + ENABLE_WALLET("Enable Google Wallet(tm) integration (default: false)", false, SettingCategory.WALLET_INTEGRATION, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM), BooleanUtils.FALSE), + WALLET_ISSUER_IDENTIFIER("Google Wallet Issuer ID", false, SettingCategory.WALLET_INTEGRATION, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), + WALLET_SERVICE_ACCOUNT_KEY("Google Wallet Service Account Key in JSON format", false, SettingCategory.WALLET_INTEGRATION, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM)), + WALLET_OVERWRITE_PREVIOUS_CLASSES_AND_EVENTS("Overwrite previous EventClass and EventObject definitions (use after code changes affecting the JSON, default: false)", false, SettingCategory.WALLET_INTEGRATION, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM), BooleanUtils.FALSE), //CHECK-IN CHECK_IN_STATS("Display check-in statistics in mobile apps", false, SettingCategory.GENERAL, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT), BooleanUtils.TRUE), @@ -248,7 +261,8 @@ public enum ConfigurationKeys { SECURITY_CSP_REPORT_ENABLED("Enable Content-Security-Policy reporting (default: false)", false, SettingCategory.GENERAL, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM), BooleanUtils.FALSE), SECURITY_CSP_REPORT_URI("Define Content-Security-Policy reporting URI (default: /report-csp-violation)", false, SettingCategory.GENERAL, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), - EMBED_ALLOWED_ORIGINS("Allowed origins for embedding the reservation process in an iFrame. Separate different origins with a newline", false, SettingCategory.GENERAL, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), + EMBED_ALLOWED_ORIGINS("Allowed origins. Separate different origins with a newline", false, SettingCategory.RESERVATION_EMBED, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM)), + EMBED_POST_MESSAGE_ORIGIN("URI to notify container (via PostMessage API) for Reservation success / cancel", false, SettingCategory.RESERVATION_EMBED, ComponentType.TEXT, false, EnumSet.of(SYSTEM)), // TRANSLATION_OVERRIDE("Translation override (json)", false, SettingCategory.TRANSLATIONS, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), @@ -268,6 +282,7 @@ public enum ConfigurationKeys { public enum SettingCategory { GENERAL("General settings"), RESERVATION_UI("Reservation Process UI"), + RESERVATION_EMBED("Embedding reservation process"), PAYMENT("Payment"), PAYMENT_STRIPE("Stripe.com settings"), PAYMENT_SAFERPAY("Saferpay settings"), @@ -281,6 +296,7 @@ public enum SettingCategory { MAP("Maps settings"), TRANSLATIONS("Translations"), PASS_INTEGRATION("Pass Integration"), + WALLET_INTEGRATION("Google Wallet Integration"), WAITING_LIST("Waiting List"), IMPORT_ATTENDEE("Import Attendees"), OPENID("Public users Authentication"), diff --git a/src/main/java/alfio/model/system/command/FinalizeReservation.java b/src/main/java/alfio/model/system/command/FinalizeReservation.java new file mode 100644 index 0000000000..4fcde06830 --- /dev/null +++ b/src/main/java/alfio/model/system/command/FinalizeReservation.java @@ -0,0 +1,91 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.system.command; + +import alfio.manager.payment.PaymentSpecification; +import alfio.model.TicketReservation.TicketReservationStatus; +import alfio.model.transaction.PaymentProxy; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; + +public class FinalizeReservation { + private final PaymentSpecification paymentSpecification; + private final PaymentProxy paymentProxy; + private final boolean sendReservationConfirmationEmail; + private final boolean sendTickets; + private final String username; + private final TicketReservationStatus originalStatus; + + @JsonCreator + public FinalizeReservation(@JsonProperty("paymentSpecification") PaymentSpecification paymentSpecification, + @JsonProperty("paymentProxy") PaymentProxy paymentProxy, + @JsonProperty("sendReservationConfirmationEmail") boolean sendReservationConfirmationEmail, + @JsonProperty("sendTickets") boolean sendTickets, + @JsonProperty("username") String username, + @JsonProperty("originalStatus") TicketReservationStatus originalStatus) { + this.paymentSpecification = paymentSpecification; + this.paymentProxy = paymentProxy; + this.sendReservationConfirmationEmail = sendReservationConfirmationEmail; + this.sendTickets = sendTickets; + this.username = username; + this.originalStatus = originalStatus; + } + + public PaymentSpecification getPaymentSpecification() { + return paymentSpecification; + } + + public PaymentProxy getPaymentProxy() { + return paymentProxy; + } + + public boolean isSendReservationConfirmationEmail() { + return sendReservationConfirmationEmail; + } + + public boolean isSendTickets() { + return sendTickets; + } + + public String getUsername() { + return username; + } + + public TicketReservationStatus getOriginalStatus() { + return originalStatus; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof FinalizeReservation)) { + return false; + } + FinalizeReservation that = (FinalizeReservation) o; + return sendReservationConfirmationEmail == that.sendReservationConfirmationEmail + && sendTickets == that.sendTickets + && paymentSpecification.equals(that.paymentSpecification) + && paymentProxy == that.paymentProxy + && Objects.equals(username, that.username); + } + + @Override + public int hashCode() { + return Objects.hash(paymentSpecification, paymentProxy, sendReservationConfirmationEmail, sendTickets, username); + } +} diff --git a/src/main/java/alfio/model/system/command/InvalidateAccess.java b/src/main/java/alfio/model/system/command/InvalidateAccess.java new file mode 100644 index 0000000000..bbc6f0e3ca --- /dev/null +++ b/src/main/java/alfio/model/system/command/InvalidateAccess.java @@ -0,0 +1,48 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.model.system.command; + +import alfio.model.Event; +import alfio.model.Ticket; +import alfio.model.metadata.TicketMetadataContainer; + +/** + * Signals that access for the ticket must be invalidated on external systems + */ +public class InvalidateAccess { + private final Ticket ticket; + private final TicketMetadataContainer ticketMetadataContainer; + private final Event event; + + public InvalidateAccess(Ticket ticket, TicketMetadataContainer ticketMetadataContainer, Event event) { + this.ticket = ticket; + this.ticketMetadataContainer = ticketMetadataContainer; + this.event = event; + } + + public Ticket getTicket() { + return ticket; + } + + public TicketMetadataContainer getTicketMetadataContainer() { + return ticketMetadataContainer; + } + + public Event getEvent() { + return event; + } +} diff --git a/src/main/java/alfio/model/transaction/Transaction.java b/src/main/java/alfio/model/transaction/Transaction.java index 40db3845cc..1effc739bc 100644 --- a/src/main/java/alfio/model/transaction/Transaction.java +++ b/src/main/java/alfio/model/transaction/Transaction.java @@ -28,6 +28,7 @@ @Getter public class Transaction { + public static final String NOTES_KEY = "transactionNotes"; public enum Status { PENDING, OFFLINE_MATCHING_PAYMENT_FOUND, @@ -94,4 +95,12 @@ public boolean isPotentialMatch() { public String getFormattedAmount() { return MonetaryUtil.formatCents(priceInCents, currency); } + + public String getNotes() { + return metadata == null ? null : metadata.get(NOTES_KEY); + } + + public boolean isTimestampEditable() { + return paymentProxy == PaymentProxy.OFFLINE || paymentProxy == PaymentProxy.ON_SITE; + } } diff --git a/src/main/java/alfio/model/transaction/TransactionRequest.java b/src/main/java/alfio/model/transaction/TransactionRequest.java index 821bcf4b1e..b9450114a0 100644 --- a/src/main/java/alfio/model/transaction/TransactionRequest.java +++ b/src/main/java/alfio/model/transaction/TransactionRequest.java @@ -18,16 +18,11 @@ import alfio.model.BillingDetails; import alfio.model.TotalPrice; -import lombok.Data; -@Data -public class TransactionRequest { +public record TransactionRequest(TotalPrice price, BillingDetails billingDetails) { private static final TransactionRequest EMPTY = new TransactionRequest(null, null); - private final TotalPrice price; - private final BillingDetails billingDetails; - public static TransactionRequest empty() { return EMPTY; } diff --git a/src/main/java/alfio/model/transaction/token/MollieToken.java b/src/main/java/alfio/model/transaction/token/MollieToken.java index 94fd3ac62c..a4384aacbc 100644 --- a/src/main/java/alfio/model/transaction/token/MollieToken.java +++ b/src/main/java/alfio/model/transaction/token/MollieToken.java @@ -19,14 +19,17 @@ import alfio.model.transaction.PaymentMethod; import alfio.model.transaction.PaymentProxy; import alfio.model.transaction.PaymentToken; -import lombok.AllArgsConstructor; -@AllArgsConstructor public class MollieToken implements PaymentToken { private final String paymentId; private final PaymentMethod paymentMethod; + public MollieToken(String paymentId, PaymentMethod paymentMethod) { + this.paymentId = paymentId; + this.paymentMethod = paymentMethod; + } + @Override public String getToken() { return paymentId; diff --git a/src/main/java/alfio/model/transaction/token/PayPalToken.java b/src/main/java/alfio/model/transaction/token/PayPalToken.java index 259ea25664..3a8d5fba8a 100644 --- a/src/main/java/alfio/model/transaction/token/PayPalToken.java +++ b/src/main/java/alfio/model/transaction/token/PayPalToken.java @@ -20,9 +20,7 @@ import alfio.model.transaction.PaymentProxy; import alfio.model.transaction.PaymentToken; import lombok.Getter; -import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor @Getter public class PayPalToken implements PaymentToken { @@ -30,6 +28,12 @@ public class PayPalToken implements PaymentToken { private final String paymentId; private final String hmac; + public PayPalToken(String payerId, String paymentId, String hmac) { + this.payerId = payerId; + this.paymentId = paymentId; + this.hmac = hmac; + } + @Override public String getToken() { return paymentId; diff --git a/src/main/java/alfio/model/transaction/token/StripeCreditCardToken.java b/src/main/java/alfio/model/transaction/token/StripeCreditCardToken.java index ce6d0c2931..34db799521 100644 --- a/src/main/java/alfio/model/transaction/token/StripeCreditCardToken.java +++ b/src/main/java/alfio/model/transaction/token/StripeCreditCardToken.java @@ -19,13 +19,15 @@ import alfio.model.transaction.PaymentMethod; import alfio.model.transaction.PaymentProxy; import alfio.model.transaction.PaymentToken; -import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor public class StripeCreditCardToken implements PaymentToken { private final String token; + public StripeCreditCardToken(String token) { + this.token = token; + } + @Override public String getToken() { return token; diff --git a/src/main/java/alfio/model/transaction/token/StripeSCACreditCardToken.java b/src/main/java/alfio/model/transaction/token/StripeSCACreditCardToken.java index 20cf80dcc1..1b5160ae10 100644 --- a/src/main/java/alfio/model/transaction/token/StripeSCACreditCardToken.java +++ b/src/main/java/alfio/model/transaction/token/StripeSCACreditCardToken.java @@ -20,9 +20,7 @@ import alfio.model.transaction.PaymentProxy; import alfio.model.transaction.TransactionInitializationToken; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; -@AllArgsConstructor public class StripeSCACreditCardToken implements TransactionInitializationToken { @JsonIgnore @@ -31,6 +29,12 @@ public class StripeSCACreditCardToken implements TransactionInitializationToken private final String chargeId; private final String clientSecret; + public StripeSCACreditCardToken(String paymentIntentId, String chargeId, String clientSecret) { + this.paymentIntentId = paymentIntentId; + this.chargeId = chargeId; + this.clientSecret = clientSecret; + } + @Override public String getToken() { return chargeId; diff --git a/src/main/java/alfio/model/transaction/webhook/EmptyWebhookPayload.java b/src/main/java/alfio/model/transaction/webhook/EmptyWebhookPayload.java index 2aacfe3af8..6bb87de796 100644 --- a/src/main/java/alfio/model/transaction/webhook/EmptyWebhookPayload.java +++ b/src/main/java/alfio/model/transaction/webhook/EmptyWebhookPayload.java @@ -17,18 +17,21 @@ package alfio.model.transaction.webhook; import alfio.model.transaction.TransactionWebhookPayload; -import lombok.AllArgsConstructor; /** * Special {@link alfio.model.transaction.TransactionWebhookPayload} for providers that don't send a payload * along with the Webhook */ -@AllArgsConstructor public class EmptyWebhookPayload implements TransactionWebhookPayload { private final String reservationId; private final Status status; + public EmptyWebhookPayload(String reservationId, Status status) { + this.reservationId = reservationId; + this.status = status; + } + @Override public String getPayload() { return "empty"; diff --git a/src/main/java/alfio/model/transaction/webhook/MollieWebhookPayload.java b/src/main/java/alfio/model/transaction/webhook/MollieWebhookPayload.java index 89d53bdc6b..676075f4d1 100644 --- a/src/main/java/alfio/model/transaction/webhook/MollieWebhookPayload.java +++ b/src/main/java/alfio/model/transaction/webhook/MollieWebhookPayload.java @@ -18,9 +18,7 @@ import alfio.model.PurchaseContext; import alfio.model.transaction.TransactionWebhookPayload; -import lombok.AllArgsConstructor; -@AllArgsConstructor public class MollieWebhookPayload implements TransactionWebhookPayload { private final String paymentId; @@ -28,6 +26,13 @@ public class MollieWebhookPayload implements TransactionWebhookPayload { private final String purchaseContextIdentifier; private final String reservationId; + public MollieWebhookPayload(String paymentId, PurchaseContext.PurchaseContextType purchaseContextType, String purchaseContextIdentifier, String reservationId) { + this.paymentId = paymentId; + this.purchaseContextType = purchaseContextType; + this.purchaseContextIdentifier = purchaseContextIdentifier; + this.reservationId = reservationId; + } + @Override public String getPayload() { return getPaymentId(); diff --git a/src/main/java/alfio/model/transaction/webhook/StripeChargeTransactionWebhookPayload.java b/src/main/java/alfio/model/transaction/webhook/StripeChargeTransactionWebhookPayload.java index 653782dcff..0471a45584 100644 --- a/src/main/java/alfio/model/transaction/webhook/StripeChargeTransactionWebhookPayload.java +++ b/src/main/java/alfio/model/transaction/webhook/StripeChargeTransactionWebhookPayload.java @@ -18,14 +18,17 @@ import alfio.model.transaction.TransactionWebhookPayload; import com.stripe.model.Charge; -import lombok.AllArgsConstructor; -@AllArgsConstructor public class StripeChargeTransactionWebhookPayload implements TransactionWebhookPayload { private final String type; private final Charge payload; + public StripeChargeTransactionWebhookPayload(String type, Charge payload) { + this.type = type; + this.payload = payload; + } + @Override public Charge getPayload() { return payload; diff --git a/src/main/java/alfio/model/transaction/webhook/StripePaymentIntentWebhookPayload.java b/src/main/java/alfio/model/transaction/webhook/StripePaymentIntentWebhookPayload.java index 395881c532..dd17185ef6 100644 --- a/src/main/java/alfio/model/transaction/webhook/StripePaymentIntentWebhookPayload.java +++ b/src/main/java/alfio/model/transaction/webhook/StripePaymentIntentWebhookPayload.java @@ -18,14 +18,17 @@ import alfio.model.transaction.TransactionWebhookPayload; import com.stripe.model.PaymentIntent; -import lombok.AllArgsConstructor; -@AllArgsConstructor public class StripePaymentIntentWebhookPayload implements TransactionWebhookPayload { private final String type; private final PaymentIntent payload; + public StripePaymentIntentWebhookPayload(String type, PaymentIntent payload) { + this.type = type; + this.payload = payload; + } + @Override public PaymentIntent getPayload() { return payload; diff --git a/src/main/java/alfio/model/user/Organization.java b/src/main/java/alfio/model/user/Organization.java index 304634d7ad..9edf811c27 100644 --- a/src/main/java/alfio/model/user/Organization.java +++ b/src/main/java/alfio/model/user/Organization.java @@ -57,12 +57,10 @@ public Organization(@Column("id") int id, public boolean equals(Object o) { if (this == o) return true; - if (! (o instanceof Organization)) { + if (! (o instanceof Organization that)) { return false; } - Organization that = (Organization) o; - return new EqualsBuilder() .append(id, that.id) .isEquals(); @@ -79,7 +77,7 @@ public int hashCode() { * @deprecated use {@link #getExternalId()} * @return the external ID, if present */ - @Deprecated + @Deprecated(forRemoval = true) public String getNameOpenId() { return externalId; } diff --git a/src/main/java/alfio/model/user/PublicUserProfile.java b/src/main/java/alfio/model/user/PublicUserProfile.java index 7b3d946622..5261b6ee28 100644 --- a/src/main/java/alfio/model/user/PublicUserProfile.java +++ b/src/main/java/alfio/model/user/PublicUserProfile.java @@ -24,8 +24,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import lombok.Getter; -import java.util.AbstractMap; -import java.util.List; import java.util.Map; @Getter diff --git a/src/main/java/alfio/model/user/Role.java b/src/main/java/alfio/model/user/Role.java index 41e64a0ef7..9e62ecf23d 100644 --- a/src/main/java/alfio/model/user/Role.java +++ b/src/main/java/alfio/model/user/Role.java @@ -19,21 +19,23 @@ import lombok.Getter; import java.util.Arrays; +import java.util.EnumSet; +import java.util.Set; @Getter public enum Role { - ADMIN("ROLE_ADMIN", "Administrator", RoleTarget.ADMIN), - OWNER("ROLE_OWNER", "Organization owner", RoleTarget.USER), - SUPERVISOR("ROLE_SUPERVISOR", "Check-in supervisor", RoleTarget.USER), - OPERATOR("ROLE_OPERATOR", "Check-in operator", RoleTarget.API_KEY), - SPONSOR("ROLE_SPONSOR", "Sponsor", RoleTarget.API_KEY), - API_CONSUMER("ROLE_API_CLIENT", "API Client", RoleTarget.API_KEY); + ADMIN("ROLE_ADMIN", "Administrator", EnumSet.of(RoleTarget.ADMIN)), + OWNER("ROLE_OWNER", "Organization owner", EnumSet.of(RoleTarget.USER)), + SUPERVISOR("ROLE_SUPERVISOR", "Check-in supervisor", EnumSet.of(RoleTarget.USER, RoleTarget.API_KEY)), + OPERATOR("ROLE_OPERATOR", "Check-in operator", EnumSet.of(RoleTarget.API_KEY)), + SPONSOR("ROLE_SPONSOR", "Sponsor", EnumSet.of(RoleTarget.API_KEY)), + API_CONSUMER("ROLE_API_CLIENT", "API Client", EnumSet.of(RoleTarget.API_KEY)); private final String roleName; private final String description; - private final RoleTarget target; + private final Set target; - Role(String roleName, String description, RoleTarget target) { + Role(String roleName, String description, Set target) { this.roleName = roleName; this.description = description; this.target = target; diff --git a/src/main/java/alfio/model/user/UserWithOrganizations.java b/src/main/java/alfio/model/user/UserWithOrganizations.java index d7b956ee1f..496f6c503d 100644 --- a/src/main/java/alfio/model/user/UserWithOrganizations.java +++ b/src/main/java/alfio/model/user/UserWithOrganizations.java @@ -17,12 +17,10 @@ package alfio.model.user; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.RequiredArgsConstructor; import lombok.experimental.Delegate; import java.util.List; -@RequiredArgsConstructor public class UserWithOrganizations { @Delegate @JsonIgnore @@ -30,6 +28,12 @@ public class UserWithOrganizations { private final List memberOf; private final List roles; + public UserWithOrganizations(User user, List memberOf, List roles) { + this.user = user; + this.memberOf = memberOf; + this.roles = roles; + } + public List getMemberOf() { return memberOf; } diff --git a/src/main/java/alfio/model/user/join/UserOrganization.java b/src/main/java/alfio/model/user/join/UserOrganization.java index 4da0ab41c5..e4f76c9019 100644 --- a/src/main/java/alfio/model/user/join/UserOrganization.java +++ b/src/main/java/alfio/model/user/join/UserOrganization.java @@ -17,16 +17,6 @@ package alfio.model.user.join; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; -@Getter -public class UserOrganization { - - private final int userId; - private final int organizationId; - - public UserOrganization(@Column("user_id") int userId, @Column("org_id") int organizationId) { - this.userId = userId; - this.organizationId = organizationId; - } +public record UserOrganization(@Column("user_id") int userId, @Column("org_id") int organizationId) { } diff --git a/src/main/java/alfio/repository/AdditionalServiceItemRepository.java b/src/main/java/alfio/repository/AdditionalServiceItemRepository.java index e576d1a9f2..fc180821b7 100644 --- a/src/main/java/alfio/repository/AdditionalServiceItemRepository.java +++ b/src/main/java/alfio/repository/AdditionalServiceItemRepository.java @@ -68,7 +68,7 @@ List getAdditionalServicesBookedForReservation(@Bind("r "select" + " ai.uuid ai_uuid, ai.creation ai_creation, ai.last_modified ai_last_modified, ai.final_price_cts ai_final_price_cts, ai.currency_code ai_currency_code, ai.vat_cts ai_vat_cts, ai.discount_cts ai_discount_cts," + " tr.id tr_uuid, tr.first_name tr_first_name, tr.last_name tr_last_name, tr.email_address tr_email_address," + - " asv.service_type as_type, asd.value as_title" + + " asv.service_type as_type, asd.value as_title, ai.status as ai_status " + " from additional_service_item ai" + " join additional_service asv on ai.additional_service_id_fk = asv.id" + " join tickets_reservation tr on ai.tickets_reservation_uuid = tr.id" + @@ -76,7 +76,8 @@ List getAdditionalServicesBookedForReservation(@Bind("r " where ai.event_id_fk = :eventId" + " and asv.service_type = :additionalServiceType" + " and asd.type = 'TITLE'" + - " and asd.locale = :locale" + " and asd.locale = :locale " + + " and ai.status in ('ACQUIRED', 'CHECKED_IN', 'TO_BE_PAID') " ) List getAdditionalServicesOfTypeForEvent(@Bind("eventId") int eventId, @Bind("additionalServiceType") String additionalServiceType, diff --git a/src/main/java/alfio/repository/AdditionalServiceRepository.java b/src/main/java/alfio/repository/AdditionalServiceRepository.java index 453c768630..59a4d301ae 100644 --- a/src/main/java/alfio/repository/AdditionalServiceRepository.java +++ b/src/main/java/alfio/repository/AdditionalServiceRepository.java @@ -17,6 +17,8 @@ package alfio.repository; import alfio.model.AdditionalService; +import alfio.model.AdditionalServiceItem; +import alfio.model.AdditionalServiceItem.AdditionalServiceItemStatus; import ch.digitalfondue.npjt.*; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -32,12 +34,16 @@ public interface AdditionalServiceRepository { NamedParameterJdbcTemplate getJdbcTemplate(); - default Map getCount(int eventId) { - Map res = new HashMap<>(); - getJdbcTemplate().query("select count(*) as cnt, additional_service_id_fk from additional_service_item where event_id_fk = :eventId group by additional_service_id_fk", + default Map> getCount(int eventId) { + Map> res = new HashMap<>(); + getJdbcTemplate().query("select count(*) as cnt, additional_service_id_fk, status from additional_service_item where event_id_fk = :eventId group by additional_service_id_fk, status", Collections.singletonMap("eventId", eventId), rse -> { - res.put(rse.getInt("additional_service_id_fk"), rse.getInt("cnt")); + var additionalServiceId = rse.getInt("additional_service_id_fk"); + res.putIfAbsent(additionalServiceId, new EnumMap<>(AdditionalServiceItem.AdditionalServiceItemStatus.class)); + var statusCount = res.get(additionalServiceId); + var status = AdditionalServiceItem.AdditionalServiceItemStatus.valueOf(rse.getString("status")); + statusCount.put(status, rse.getInt("cnt")); } ); return res; diff --git a/src/main/java/alfio/repository/AdditionalServiceTextRepository.java b/src/main/java/alfio/repository/AdditionalServiceTextRepository.java index ffbcc0722e..6150f8d750 100644 --- a/src/main/java/alfio/repository/AdditionalServiceTextRepository.java +++ b/src/main/java/alfio/repository/AdditionalServiceTextRepository.java @@ -56,17 +56,17 @@ default Map>> g Map>> res = new HashMap<>(); findAllByAdditionalServiceIds(additionalServiceIds).forEach(t -> { - var id = t.getAdditionalServiceId(); + var id = t.additionalServiceId(); if (!res.containsKey(id)) { res.put(id, new EnumMap<>(AdditionalServiceText.TextType.class)); } - if(!res.get(id).containsKey(t.getType())) { - res.get(id).put(t.getType(), new HashMap<>()); + if(!res.get(id).containsKey(t.type())) { + res.get(id).put(t.type(), new HashMap<>()); } - res.get(id).get(t.getType()).put(t.getLocale(), t.getValue()); + res.get(id).get(t.type()).put(t.locale(), t.value()); }); return res; diff --git a/src/main/java/alfio/repository/AuditingRepository.java b/src/main/java/alfio/repository/AuditingRepository.java index 9357a78ab2..34614fc49e 100644 --- a/src/main/java/alfio/repository/AuditingRepository.java +++ b/src/main/java/alfio/repository/AuditingRepository.java @@ -74,6 +74,11 @@ default int insert(String reservationId, Integer userId, PurchaseContext p, Audi @Query("select count(*) from auditing_user where reservation_id = :reservationId and event_type = :eventType") Integer countAuditsOfTypeForReservation(@Bind("reservationId") String reservationId, @Bind("eventType") Audit.EventType eventType); + @Query("select count(*) from auditing_user where reservation_id = :reservationId and entity_id = :ticketId::text and event_type = :eventType") + Integer countAuditsOfTypeForTicket(@Bind("reservationId") String reservationId, + @Bind("ticketId") int ticketId, + @Bind("eventType") Audit.EventType eventType); + @Query("select count(*) from auditing_user where reservation_id = :reservationId and event_type in (:eventTypes) and date_trunc('day', :referenceDate::timestamp) = date_trunc('day', event_time)") Integer countAuditsOfTypesInTheSameDay(@Bind("reservationId") String reservationId, @Bind("eventTypes") Collection eventTypes, @Bind("referenceDate") ZonedDateTime date); diff --git a/src/main/java/alfio/repository/BillingDocumentRepository.java b/src/main/java/alfio/repository/BillingDocumentRepository.java index 1053075640..adc77238b0 100644 --- a/src/main/java/alfio/repository/BillingDocumentRepository.java +++ b/src/main/java/alfio/repository/BillingDocumentRepository.java @@ -26,6 +26,11 @@ @QueryRepository public interface BillingDocumentRepository { + String LOAD_ALL_BY_EVENT_ID = "select a.* from billing_document a inner join" + + " (select max(generation_ts) as time,reservation_id_fk from billing_document where status = 'VALID' and type = 'INVOICE' and event_id_fk = :eventId group by reservation_id_fk) b" + + " on a.generation_ts = b.time and a.reservation_id_fk = b.reservation_id_fk" + + " union select * from billing_document where status = 'VALID' and event_id_fk = :eventId and type <> 'INVOICE'"; + @Query("select * from billing_document where reservation_id_fk = :reservationId and status = 'VALID' order by generation_ts desc limit 1") Optional findLatestByReservationId(@Bind("reservationId") String reservationId); @@ -62,15 +67,12 @@ AffectedRowCountAndKey insert(@Bind("eventId") Integer eventId, " on a.generation_ts = b.time and a.reservation_id_fk = b.reservation_id_fk") List findAllOfTypeForEvent(@Bind("type") BillingDocument.Type type, @Bind("eventId") int eventId); - @Query( - "select a.* from billing_document a inner join " + - "(select max(generation_ts) as time,reservation_id_fk from billing_document where status = 'VALID' and type = 'INVOICE' and event_id_fk = :eventId group by reservation_id_fk) b" + - " on a.generation_ts = b.time and a.reservation_id_fk = b.reservation_id_fk" + - " union select * from billing_document where status = 'VALID' and event_id_fk = :eventId and type <> 'INVOICE'" + - " order by reservation_id_fk, generation_ts" - ) + @Query(LOAD_ALL_BY_EVENT_ID + " order by reservation_id_fk, generation_ts") List findAllForEvent(@Bind("eventId") int eventId); + @Query("select count(*) from (" + LOAD_ALL_BY_EVENT_ID + ") docs") + Integer countAllForEvent(@Bind("eventId") int eventId); + @Query("delete from billing_document where reservation_id_fk = :reservationId") int deleteForReservation(@Bind("reservationId") String reservationId); diff --git a/src/main/java/alfio/repository/EventAdminRepository.java b/src/main/java/alfio/repository/EventAdminRepository.java index 1f44b84aff..d64d7386be 100644 --- a/src/main/java/alfio/repository/EventAdminRepository.java +++ b/src/main/java/alfio/repository/EventAdminRepository.java @@ -37,7 +37,7 @@ public interface EventAdminRepository { */ default boolean existsBySlug(String slug) { var jdbcTemplate = getJdbcTemplate(); - boolean rlsEnabled = Boolean.TRUE.equals(jdbcTemplate.queryForObject("select coalesce(current_setting('alfio.checkRowAccess', true), 'false')", EmptySqlParameterSource.INSTANCE, Boolean.class)); + boolean rlsEnabled = Boolean.TRUE.equals(jdbcTemplate.queryForObject("select coalesce(current_setting('alfio.checkRowAccess', true), 'false') = 'true'", EmptySqlParameterSource.INSTANCE, Boolean.class)); if (rlsEnabled) { jdbcTemplate.queryForObject("select set_config('alfio.checkRowAccess', 'false', true)", EmptySqlParameterSource.INSTANCE, Boolean.class); } diff --git a/src/main/java/alfio/repository/EventDescriptionRepository.java b/src/main/java/alfio/repository/EventDescriptionRepository.java index 5e7ef99dfb..9f244d2d63 100644 --- a/src/main/java/alfio/repository/EventDescriptionRepository.java +++ b/src/main/java/alfio/repository/EventDescriptionRepository.java @@ -36,11 +36,11 @@ public interface EventDescriptionRepository { List findDescriptionByEventId(@Bind("eventId") int eventId); default Map findByEventIdAsMap(int eventId) { - return findByEventId(eventId).stream().collect(Collectors.toMap(EventDescription::getLocale, EventDescription::getDescription)); + return findByEventId(eventId).stream().collect(Collectors.toMap(EventDescription::locale, EventDescription::description)); } default Map findDescriptionByEventIdAsMap(int eventId) { - return findDescriptionByEventId(eventId).stream().collect(Collectors.toMap(EventDescription.LocaleDescription::getLocale, EventDescription.LocaleDescription::getDescription)); + return findDescriptionByEventId(eventId).stream().collect(Collectors.toMap(EventDescription.LocaleDescription::locale, EventDescription.LocaleDescription::description)); } @Query("select description from event_description_text where event_id_fk = :eventId and type = :type and locale = :locale") diff --git a/src/main/java/alfio/repository/EventRepository.java b/src/main/java/alfio/repository/EventRepository.java index e5351ca83e..50cef66a80 100644 --- a/src/main/java/alfio/repository/EventRepository.java +++ b/src/main/java/alfio/repository/EventRepository.java @@ -21,9 +21,6 @@ import alfio.model.metadata.AlfioMetadata; import alfio.model.support.JSONData; import ch.digitalfondue.npjt.*; -import org.springframework.jdbc.core.namedparam.EmptySqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.SimpleJdbcCall; import java.math.BigDecimal; import java.time.ZoneId; @@ -180,9 +177,13 @@ int updatePrices(@Bind("currency") String currency, @Query("select available_seats from events_statistics where id = :eventId") Integer countExistingTickets(@Bind("eventId") int eventId); + @Query("select count(*) from event") + Integer countEvents(); @Query(value = "update event set status = 'DISABLED' where org_id in (select org_id from j_user_organization where user_id in (:userIds)) returning id", type = QueryType.MODIFYING_WITH_RETURN) List disableEventsForUsers(@Bind("userIds") Collection userIds); + @Query(value = "update event set status = 'DISABLED' where org_id = :orgId returning id", type = QueryType.MODIFYING_WITH_RETURN) + List disableEventsForOrganization(@Bind("orgId") int orgId); @Query("select coalesce(sum(final_price_cts),0) from tickets_reservation where event_id_fk = :eventId and status = 'COMPLETE'") long getGrossIncome(@Bind("eventId") int eventId); @@ -212,4 +213,8 @@ List findVisibleBySearchOptions(@Bind("subscriptionId") UUID subscription @Bind("organizer") Integer organizer, @Bind("organizerSlug") String organizerSlug, @Bind("tags") List tags); + + @Query("select id from event where short_name in (:shortNames) and org_id = :orgId") + List findIdsByShortNames(@Bind("shortNames") List eventShortNames, + @Bind("orgId") int organizationId); } diff --git a/src/main/java/alfio/repository/ExportRepository.java b/src/main/java/alfio/repository/ExportRepository.java new file mode 100644 index 0000000000..31ca8a6873 --- /dev/null +++ b/src/main/java/alfio/repository/ExportRepository.java @@ -0,0 +1,85 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.repository; + +import alfio.model.ReservationsByEvent; +import ch.digitalfondue.npjt.Bind; +import ch.digitalfondue.npjt.Query; +import ch.digitalfondue.npjt.QueryRepository; +import ch.digitalfondue.npjt.QueryType; + +import java.time.ZonedDateTime; +import java.util.List; + +@QueryRepository +public interface ExportRepository { + @Query(type = QueryType.SELECT, value = "with tickets as (" + + " select tr_id, jsonb_agg(jsonb_build_object(" + + " 'id', t_uuid," + + " 'firstName', t_first_name," + + " 'lastName', t_last_name," + + " 'type', tc_name," + + " 'status', t_status," + + " 'srcPriceCts', t_src_price_cts," + + " 'taxCts', t_vat_cts," + + " 'taxStatus', t_vat_status," + + " 'finalPriceCts', t_final_price_cts" + + " )) items" + + " from checkin_ticket_event_and_category_info" + + " group by 1)," + + " reservations as (" + + " select distinct event_id_fk, id, invoice_number, first_name," + + " billing_address_company, vat_nr, vat_country," + + " last_name, email_address, payment_method, currency_code, invoicing_additional_information#>>'{italianEInvoicing,fiscalCode}' as tax_code," + + " confirmation_ts, final_price_cts, src_price_cts, vat_cts, vat_status from tickets_reservation" + + " where status in ('OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT', 'COMPLETE', 'CANCELLED')" + + " and confirmation_ts between :startTs and :endTs" + + " and event_id_fk is not null" + + " )," + + " reservations_event as (" + + " select tr.event_id_fk e_id, jsonb_agg(jsonb_build_object(" + + " 'id', tr.id," + + " 'invoiceNumber', tr.invoice_number," + + " 'firstName', tr.first_name," + + " 'lastName', tr.last_name," + + " 'email', tr.email_address," + + " 'paymentType', tr.payment_method," + + " 'finalPriceCts', tr.final_price_cts," + + " 'currency', tr.currency_code," + + " 'taxId', tr.vat_nr," + + " 'taxCountry', tr.vat_country," + + " 'companyName', tr.billing_address_company," + + " 'srcPriceCts', tr.src_price_cts," + + " 'taxCts', tr.vat_cts," + + " 'taxStatus', tr.vat_status," + + " 'taxCode', tr.tax_code," + + " 'confirmationTimestamp', to_char(tr.confirmation_ts at time zone 'UTC', 'YYYY-MM-DD') || 'T' || to_char(tr.confirmation_ts at time zone 'UTC', 'HH24:MI:SS.MSZ')," + + " 'tickets', t.items" + + " )) as reservations" + + " from reservations tr" + + " join tickets t on t.tr_id = tr.id" + + " group by 1" + + " )" + + " select e.id as event_id, e.short_name as event_short_name, e.display_name as event_display_name, tr.reservations" + + " from event e" + + " join reservations_event tr on e.id = tr.e_id" + + " where e.org_id in (:orgIds)" + + " order by 1") + List allReservationsForInterval(@Bind("startTs") ZonedDateTime from, + @Bind("endTs") ZonedDateTime to, + @Bind("orgIds") List orgIds); +} diff --git a/src/main/java/alfio/repository/GroupRepository.java b/src/main/java/alfio/repository/GroupRepository.java index 1e1bb4f573..2f64f39fe7 100644 --- a/src/main/java/alfio/repository/GroupRepository.java +++ b/src/main/java/alfio/repository/GroupRepository.java @@ -28,6 +28,8 @@ import java.util.Optional; import java.util.UUID; +import static org.apache.commons.text.StringEscapeUtils.escapeHtml4; + @QueryRepository public interface GroupRepository { @@ -66,7 +68,9 @@ AffectedRowCountAndKey createConfiguration(@Bind("groupId") int groupId default int[] insert(int groupId, List members) { MapSqlParameterSource[] params = members.stream() - .map(i -> new MapSqlParameterSource("groupId", groupId).addValue("value", i.getValue().toLowerCase()).addValue("description", i.getDescription())) + .map(i -> new MapSqlParameterSource("groupId", groupId) + .addValue("value", i.getValue().toLowerCase()) + .addValue("description", escapeHtml4(i.getDescription()))) .toArray(MapSqlParameterSource[]::new); return getNamedParameterJdbcTemplate().batchUpdate("insert into group_member(a_group_id_fk, value, description) values(:groupId, :value, :description)", params); diff --git a/src/main/java/alfio/repository/OrganizationDeleterRepository.java b/src/main/java/alfio/repository/OrganizationDeleterRepository.java new file mode 100644 index 0000000000..c675ed6de5 --- /dev/null +++ b/src/main/java/alfio/repository/OrganizationDeleterRepository.java @@ -0,0 +1,123 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.repository; + +import ch.digitalfondue.npjt.Bind; +import ch.digitalfondue.npjt.Query; +import ch.digitalfondue.npjt.QueryRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +@QueryRepository +public interface OrganizationDeleterRepository { + + Logger LOGGER = LoggerFactory.getLogger(OrganizationDeleterRepository.class); + String SELECT_EMPTY_ORGANIZATIONS = "select distinct(org_id) from j_user_organization where org_id in(:organizationIds)"; + + @Query("delete from auditing where organization_id_fk in(:organizationIds)" + + " and organization_id_fk not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteAuditingForEmptyOrganizations(@Bind("organizationIds") List organizationIds); + + @Query("delete from invoice_sequences where organization_id_fk in(:organizationIds)" + + " and organization_id_fk not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteInvoiceSequencesForEmptyOrganizations(@Bind("organizationIds") List organizationIds); + + @Query("delete from a_group where organization_id_fk in(:organizationIds)" + + " and organization_id_fk not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteGroupsForEmptyOrganizations(@Bind("organizationIds") List organizationIds); + + @Query("delete from group_member where organization_id_fk in(:organizationIds)" + + " and organization_id_fk not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteGroupMembersForEmptyOrganizations(@Bind("organizationIds") List organizationIds); + + @Query("delete from configuration_organization where organization_id_fk in(:organizationIds)" + + " and organization_id_fk not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteConfigurationForEmptyOrganizations(@Bind("organizationIds") List organizationIds); + + @Query("delete from resource_organizer where organization_id_fk in(:organizationIds)" + + " and organization_id_fk not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteResourcesForEmptyOrganizations(@Bind("organizationIds") List organizationIds); + + @Query("delete from subscription where organization_id_fk in (:organizationIds)") + int deleteSubscriptions(@Bind("organizationIds") List organizationIds); + + @Query("delete from subscription_descriptor where organization_id_fk in (:organizationIds)") + int deleteSubscriptionDescriptors(@Bind("organizationIds") List organizationIds); + + @Query("delete from promo_code where organization_id_fk in (:organizationIds)") + int deletePromoCodes(@Bind("organizationIds") List organizationIds); + + @Query("delete from organization where id in(:organizationIds)" + + " and id not in (" + SELECT_EMPTY_ORGANIZATIONS + ")") + int deleteOrganizationsIfEmpty(@Bind("organizationIds") List organizationIds); + + @Query("delete from tickets_reservation where organization_id_fk in (:organizationIds)") + int deleteReservations(@Bind("organizationIds") List organizationIds); + + @Query("delete from admin_reservation_request where organization_id_fk in (:organizationIds)") + int deleteAdminReservationRequests(@Bind("organizationIds") List organizationIds); + + @Query("delete from email_message where organization_id_fk in (:organizationIds)") + int deleteEmailMessages(@Bind("organizationIds") List organizationIds); + + default void deleteEmptyOrganizations(List organizationIds) { + // delete invoice sequences + int deletedSequences = deleteInvoiceSequencesForEmptyOrganizations(organizationIds); + LOGGER.info("deleted {} invoice sequences", deletedSequences); + // delete auditing + int deletedAuditing = deleteAuditingForEmptyOrganizations(organizationIds); + LOGGER.info("deleted {} auditing rows", deletedAuditing); + // delete groups + int deletedGroupMembers = deleteGroupMembersForEmptyOrganizations(organizationIds); + int deletedGroups = deleteGroupsForEmptyOrganizations(organizationIds); + LOGGER.info("deleted {} groups and {} members", deletedGroups, deletedGroupMembers); + + // delete configuration + int deletedConfigurations = deleteConfigurationForEmptyOrganizations(organizationIds); + LOGGER.info("deleted {} configurations", deletedConfigurations); + + // delete resources + int deletedResources = deleteResourcesForEmptyOrganizations(organizationIds); + LOGGER.info("deleted {} resources", deletedResources); + + int deletedEmails = deleteEmailMessages(organizationIds); + LOGGER.info("deleted {} email messages", deletedEmails); + + // delete subscriptions + int deletedSubscriptions = deleteSubscriptions(organizationIds); + int deletedDescriptors = deleteSubscriptionDescriptors(organizationIds); + LOGGER.info("deleted {} subscription descriptors and {} subscriptions", deletedDescriptors, deletedSubscriptions); + + // delete all reservations + int deletedReservations = deleteReservations(organizationIds); + LOGGER.info("deleted {} reservations", deletedReservations); + + // delete admin reservation request + int deletedAdminReservationRequests = deleteAdminReservationRequests(organizationIds); + LOGGER.info("deleted {} adminReservationRequests", deletedAdminReservationRequests); + + // delete promo codes + int deletedPromoCodes = deletePromoCodes(organizationIds); + LOGGER.info("deleted {} promo codes", deletedPromoCodes); + + int deletedOrganizations = deleteOrganizationsIfEmpty(organizationIds); + LOGGER.info("deleted {} empty organizations", deletedOrganizations); + + } +} diff --git a/src/main/java/alfio/repository/PromoCodeDiscountRepository.java b/src/main/java/alfio/repository/PromoCodeDiscountRepository.java index 1b004ef63a..fd726451ae 100644 --- a/src/main/java/alfio/repository/PromoCodeDiscountRepository.java +++ b/src/main/java/alfio/repository/PromoCodeDiscountRepository.java @@ -17,6 +17,7 @@ package alfio.repository; import alfio.model.PromoCodeDiscount; +import alfio.model.PromoCodeUsageResult; import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; import ch.digitalfondue.npjt.QueryRepository; @@ -44,8 +45,8 @@ public interface PromoCodeDiscountRepository { @Query("select * from promo_code where id = :id") Optional findOptionalById(@Bind("id") int id); - @Query("insert into promo_code(promo_code, event_id_fk, organization_id_fk, valid_from, valid_to, discount_amount, discount_type, categories, max_usage, description, email_reference, code_type, hidden_category_id) " - + " values (:promoCode, :eventId, :organizationId, :start, :end, :discountAmount, :discountType, :categories, :maxUsage, :description, :emailReference, :codeType, :hiddenCategoryId)") + @Query("insert into promo_code(promo_code, event_id_fk, organization_id_fk, valid_from, valid_to, discount_amount, discount_type, categories, max_usage, description, email_reference, code_type, hidden_category_id, currency_code) " + + " values (:promoCode, :eventId, :organizationId, :start, :end, :discountAmount, :discountType, :categories, :maxUsage, :description, :emailReference, :codeType, :hiddenCategoryId, :currencyCode)") int addPromoCode(@Bind("promoCode") String promoCode, @Bind("eventId") Integer eventId, @Bind("organizationId") int organizationId, @@ -58,7 +59,8 @@ int addPromoCode(@Bind("promoCode") String promoCode, @Bind("description") String description, @Bind("emailReference") String emailReference, @Bind("codeType") PromoCodeDiscount.CodeType codeType, - @Bind("hiddenCategoryId") Integer hiddenCategoryId); + @Bind("hiddenCategoryId") Integer hiddenCategoryId, + @Bind("currencyCode") String currencyCode); @Query("insert into promo_code(promo_code, event_id_fk, organization_id_fk, valid_from, valid_to, discount_amount, discount_type, categories, max_usage, description, email_reference, code_type, hidden_category_id) " + " values (:promoCode, :eventId, :organizationId, :start, :end, :discountAmount, :discountType, :categories, :maxUsage, :description, :emailReference, :codeType, :hiddenCategoryId) " @@ -113,4 +115,9 @@ int updateEventPromoCode(@Bind("id") int id, @Query("select id from promo_code where code_type = 'ACCESS' and id = :id for update") Integer lockAccessCodeForUpdate(@Bind("id") int id); + + @Query("select * from promocode_usage_details where promo_code = :promoCode" + + " and (:eventId is null or :eventId = event_id)") + List findDetailedUsage(@Bind("promoCode") String promoCode, + @Bind("eventId") Integer eventId); } diff --git a/src/main/java/alfio/repository/SponsorScanRepository.java b/src/main/java/alfio/repository/SponsorScanRepository.java index 026ef1ac48..ceba579ccd 100644 --- a/src/main/java/alfio/repository/SponsorScanRepository.java +++ b/src/main/java/alfio/repository/SponsorScanRepository.java @@ -33,29 +33,31 @@ public interface SponsorScanRepository { ZonedDateTime DEFAULT_TIMESTAMP = ZonedDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC); - @Query("select creation from sponsor_scan where user_id = :userId and event_id = :eventId and ticket_id = :ticketId") - Optional getRegistrationTimestamp(@Bind("userId") int userId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId); + @Query("select creation from sponsor_scan where user_id = :userId and event_id = :eventId and ticket_id = :ticketId and operator = :operator") + Optional getRegistrationTimestamp(@Bind("userId") int userId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId, @Bind("operator") String operator); - @Query("insert into sponsor_scan (user_id, creation, event_id, ticket_id, notes, lead_status) values(:userId, :creation, :eventId, :ticketId, :notes, :leadStatus)") + @Query("insert into sponsor_scan (user_id, creation, event_id, ticket_id, notes, lead_status, operator) values(:userId, :creation, :eventId, :ticketId, :notes, :leadStatus, :operator)") int insert(@Bind("userId") int userId, @Bind("creation") ZonedDateTime creation, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId, @Bind("notes") String notes, - @Bind("leadStatus") SponsorScan.LeadStatus leadStatus); + @Bind("leadStatus") SponsorScan.LeadStatus leadStatus, + @Bind("operator") String operator); - @Query("update sponsor_scan set notes = :notes, lead_status = :leadStatus where user_id = :userId and event_id = :eventId and ticket_id = :ticketId") + @Query("update sponsor_scan set notes = :notes, lead_status = :leadStatus where user_id = :userId and event_id = :eventId and ticket_id = :ticketId and operator = :operator") int updateNotesAndLeadStatus(@Bind("userId") int userId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId, @Bind("notes") String notes, - @Bind("leadStatus") SponsorScan.LeadStatus leadStatus); + @Bind("leadStatus") SponsorScan.LeadStatus leadStatus, + @Bind("operator") String operator); @Query("select t.id t_id, t.uuid t_uuid, t.creation t_creation, t.category_id t_category_id, t.status t_status, t.event_id t_event_id," + " t.src_price_cts t_src_price_cts, t.final_price_cts t_final_price_cts, t.vat_cts t_vat_cts, t.discount_cts t_discount_cts, t.tickets_reservation_id t_tickets_reservation_id," + " t.full_name t_full_name, t.first_name t_first_name, t.last_name t_last_name, t.email_address t_email_address, t.locked_assignment t_locked_assignment," + " t.user_language t_user_language, t.ext_reference t_ext_reference, t.currency_code t_currency_code, t.tags t_tags, t.subscription_id_fk t_subscription_id, t.vat_status t_vat_status," + - " s.user_id s_user_id, s.creation s_creation, s.event_id s_event_id, s.ticket_id s_ticket_id, s.notes s_notes, s.lead_status s_lead_status, " + + " s.user_id s_user_id, s.creation s_creation, s.event_id s_event_id, s.ticket_id s_ticket_id, s.notes s_notes, s.lead_status s_lead_status, s.operator s_operator, " + " (case when s.lead_status = 'HOT' then 2 when s.lead_status = 'WARM' then 1 else 0 end) as priority"+ " from sponsor_scan s, ticket t where s.event_id = :eventId and s.user_id = :userId and s.creation > :start and s.ticket_id = t.id order by priority desc, s.creation") List loadSponsorData(@Bind("eventId") int eventId, diff --git a/src/main/java/alfio/repository/SubscriptionRepository.java b/src/main/java/alfio/repository/SubscriptionRepository.java index 0982607cc5..200a7f0845 100644 --- a/src/main/java/alfio/repository/SubscriptionRepository.java +++ b/src/main/java/alfio/repository/SubscriptionRepository.java @@ -18,6 +18,7 @@ import alfio.model.AllocationStatus; import alfio.model.PriceContainer.VatStatus; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.subscription.*; import alfio.model.subscription.SubscriptionDescriptor.SubscriptionTimeUnit; import alfio.model.subscription.SubscriptionDescriptor.SubscriptionUsageType; @@ -56,11 +57,11 @@ public interface SubscriptionRepository { @Query("insert into subscription_descriptor (" + "id, title, description, max_available, on_sale_from, on_sale_to, price_cts, vat, vat_status, currency, is_public, organization_id_fk, " + " max_entries, validity_type, validity_time_unit, validity_units, validity_from, validity_to, usage_type, terms_conditions_url, privacy_policy_url," + - " file_blob_id_fk, allowed_payment_proxies, private_key, time_zone, supports_tickets_generation) " + + " file_blob_id_fk, allowed_payment_proxies, private_key, time_zone, supports_tickets_generation, status) " + " values(:id, :title::jsonb, :description::jsonb, :maxAvailable, :onSaleFrom, :onSaleTo, :priceCts, :vat, :vatStatus::VAT_STATUS, :currency, " + " :isPublic, :organizationId, :maxEntries, :validityType::SUBSCRIPTION_VALIDITY_TYPE, :validityTimeUnit::SUBSCRIPTION_TIME_UNIT, " + " :validityUnits, :validityFrom, :validityTo, :usageType::SUBSCRIPTION_USAGE_TYPE, :tcUrl, :privacyPolicyUrl," + - " :fileBlobId, :allowedPaymentProxies::text[], :privateKey, :timeZone, :supportsTicketsGeneration)") + " :fileBlobId, :allowedPaymentProxies::text[], :privateKey, :timeZone, :supportsTicketsGeneration, 'ACTIVE')") int createSubscriptionDescriptor(@Bind("id") UUID id, @Bind("title") @JSONData Map title, @Bind("description") @JSONData Map description, @@ -130,36 +131,45 @@ int updateSubscriptionDescriptor(@Bind("title") @JSONData Map ti @Query("update subscription_descriptor set is_public = :isPublic where id = :id and organization_id_fk = :organizationId") int setPublicStatus(@Bind("id") UUID id, @Bind("organizationId") int organizationId, @Bind("isPublic") boolean isPublic); - @Query("select * from subscription_descriptor where organization_id_fk = :organizationId order by on_sale_from, on_sale_to nulls last") + @Query("update subscription_descriptor set status = 'NOT_ACTIVE' where id = :id and organization_id_fk = :organizationId") + int deactivateDescriptor(@Bind("id") UUID id, @Bind("organizationId") int organizationId); + + @Query("select * from subscription_descriptor where organization_id_fk = :organizationId" + + " and status = 'ACTIVE'" + + " order by on_sale_from, on_sale_to nulls last") List findAllByOrganizationIds(@Bind("organizationId") int organizationId); @Query("select subscription_descriptor.* from subscription_descriptor" + " join organization org on subscription_descriptor.organization_id_fk = org.id "+ - " where is_public = true and" + + " where status = 'ACTIVE' and is_public = true and" + " (max_entries > 0 or max_entries = -1) and (on_sale_from is null or :from >= on_sale_from) " + " and (on_sale_to is null or :from <= on_sale_to)" + " and (:orgSlug is null or org.slug = :orgSlug)"+ " order by on_sale_from, on_sale_to nulls last") List findAllActiveAndPublic(@Bind("from") ZonedDateTime from, @Bind("orgSlug") String organizerSlug); - @Query("select * from subscription_descriptor where id = :id and organization_id_fk = :organizationId") + @Query("select * from subscription_descriptor where status = 'ACTIVE' and id = :id and organization_id_fk = :organizationId") Optional findOne(@Bind("id") UUID id, @Bind("organizationId") int organizationId); - @Query("select * from subscription_descriptor where id = :id") + @Query("select * from subscription_descriptor where id = :id and status = 'ACTIVE'") Optional findOne(@Bind("id") UUID id); - @Query("select * from subscription_descriptor where id = (select subscription_descriptor_fk from subscription where reservation_id_fk = :reservationId)") + @Query("select * from subscription_descriptor where id = (select subscription_descriptor_fk from subscription where reservation_id_fk = :reservationId) and status = 'ACTIVE'") Optional findDescriptorByReservationId(@Bind("reservationId") String reservationId); - @Query("select * from subscription_descriptor where id = (select subscription_descriptor_fk from subscription where id = :id)") + @Query("select * from subscription_descriptor where id = (select subscription_descriptor_fk from subscription where id = :id) and status = 'ACTIVE'") SubscriptionDescriptor findDescriptorBySubscriptionId(@Bind("id") UUID subscriptionId); - @Query("select organization_id_fk from subscription_descriptor where id = (select subscription_descriptor_fk from subscription where id = :id)") + @Query("select organization_id_fk from subscription_descriptor where id = (select subscription_descriptor_fk from subscription where id = :id) and status = 'ACTIVE'") Optional findOrganizationIdForSubscription(@Bind("id") UUID subscriptionId); @Query("select * from subscription_descriptor_statistics where sd_organization_id_fk = :organizationId") List findAllWithStatistics(@Bind("organizationId") int organizationId); + @Query("select * from subscription_descriptor_statistics where sd_organization_id_fk = :organizationId and sd_id = :subscriptionDescriptorId") + Optional findOneWithStatistics(@Bind("subscriptionDescriptorId") UUID subscriptionDescriptorId, + @Bind("organizationId") int organizationId); + @Query("select exists (select 1 from subscription_event where event_id_fk = :eventId" + " and subscription_descriptor_id_fk = :subscriptionDescriptorId::uuid and organization_id_fk = :organizationId)") boolean isSubscriptionLinkedToEvent(@Bind("eventId") int eventId, @@ -182,7 +192,8 @@ List findLinkedEvents(@Bind("organizationId") int organiz @Query("select subscription_descriptor_id_fk from subscription_event where event_id_fk = :eventId and organization_id_fk = :organizationId") List findLinkedSubscriptionIds(@Bind("eventId") int eventId, @Bind("organizationId") int organizationId); - @Query("select * from subscription_descriptor where organization_id_fk = :organizationId and (on_sale_to is null or on_sale_to > now()) order by on_sale_from, on_sale_to nulls last") + @Query("select * from subscription_descriptor where status = 'ACTIVE' and organization_id_fk = :organizationId" + + " and (on_sale_to is null or on_sale_to > now()) order by on_sale_from, on_sale_to nulls last") List findActiveSubscriptionsForOrganization(@Bind("organizationId") int organizationId); @Query("delete from subscription_event where event_id_fk = :eventId and organization_id_fk = :organizationId" + @@ -191,10 +202,20 @@ int removeStaleSubscriptions(@Bind("eventId") int eventId, @Bind("organizationId") int organizationId, @Bind("descriptorIds") List currentDescriptors); + @Query("delete from subscription_event where subscription_descriptor_id_fk = :subscriptionId and organization_id_fk = :organizationId" + + " and event_id_fk not in (:eventIds)") + int removeStaleEvents(@Bind("subscriptionId") UUID subscriptionId, + @Bind("organizationId") int organizationId, + @Bind("eventIds") List eventIds); + @Query("delete from subscription_event where event_id_fk = :eventId and organization_id_fk = :organizationId") int removeAllSubscriptionsForEvent(@Bind("eventId") int eventId, @Bind("organizationId") int organizationId); + @Query("delete from subscription_event where subscription_descriptor_id_fk = :subscriptionId and organization_id_fk = :organizationId") + int removeAllLinksForSubscription(@Bind("subscriptionId") UUID subscriptionId, + @Bind("organizationId") int organizationId); + @Query(type = QueryType.TEMPLATE, value = INSERT_SUBSCRIPTION) String batchCreateSubscription(); @@ -232,7 +253,7 @@ int createSubscription(@Bind("id") UUID id, @Query("select * from subscription where reservation_id_fk = :reservationId for update") Optional findFirstSubscriptionByReservationIdForUpdate(@Bind("reservationId") String reservationId); - @Query("select exists(select 1 from subscription_descriptor where id = :id)") + @Query("select exists(select 1 from subscription_descriptor where id = :id and status = 'ACTIVE')") boolean existsById(@Bind("id") UUID subscriptionId); @Query("select exists (select id from subscription_event where event_id_fk = :eventId)") @@ -343,7 +364,8 @@ default Map> loadAvailableSubscript " and sd.supports_tickets_generation is TRUE " + " and exp.inception <= now() " + " and exp.expiration > now() " + - " and (s.max_usage = -1 or s.max_usage > u.usage) " + + " and (s.max_entries = -1 or s.max_entries > u.usage) " + + " and (select count(*) from ticket_category where event_id = e.id and tc_status = 'ACTIVE') > 0" + " order by e.id", paramSource, rse -> { int eId = rse.getInt("event_id"); if (!result.containsKey(eId)) { @@ -364,4 +386,14 @@ default Map> loadAvailableSubscript @Query("update subscription set src_price_cts = :price where subscription_descriptor_fk = :descriptorId and status = 'FREE'") int updatePriceForSubscriptions(@Bind("descriptorId") UUID subscriptionDescriptorId, @Bind("price") int priceCts); + + @Query("update subscription set max_entries = :maxEntries, max_usage = :maxEntries where subscription_descriptor_fk = :descriptorId") + int updateMaxEntriesForSubscriptions(@Bind("descriptorId") UUID subscriptionDescriptorId, @Bind("maxEntries") int maxEntries); + + @Query("update subscription set metadata = :metadata::jsonb where id = :id") + int setMetadataForSubscription(@Bind("id") UUID subscriptionId, @Bind("metadata") @JSONData SubscriptionMetadata metadata); + + @Query("select metadata from subscription where id = :id") + @JSONData + SubscriptionMetadata getSubscriptionMetadata(@Bind("id") UUID subscriptionId); } diff --git a/src/main/java/alfio/repository/TicketCategoryRepository.java b/src/main/java/alfio/repository/TicketCategoryRepository.java index 09f1a9eb5b..bccd49a78d 100644 --- a/src/main/java/alfio/repository/TicketCategoryRepository.java +++ b/src/main/java/alfio/repository/TicketCategoryRepository.java @@ -34,6 +34,8 @@ @QueryRepository public interface TicketCategoryRepository { + String CHECK_ACTIVE = "event_id = :eventId and tc_status = 'ACTIVE'"; + @Query("insert into ticket_category(inception, expiration, name, max_tickets, price_cts, src_price_cts, access_restricted, tc_status, event_id, bounded, category_code, valid_checkin_from, valid_checkin_to, ticket_validity_start, ticket_validity_end, ordinal, ticket_checkin_strategy, metadata, ticket_access_type) " + "values(:inception, :expiration, :name, :max_tickets, 0, :price, :accessRestricted, 'ACTIVE', :eventId, :bounded, :code, :validCheckInFrom, :validCheckInTo, :ticketValidityStart, :ticketValidityEnd, :ordinal, :ticketCheckInStrategy, :metadata::jsonb, :ticketAccessType::ticket_access_type)") @AutoGeneratedKey("id") @@ -55,13 +57,13 @@ AffectedRowCountAndKey insert(@Bind("inception") ZonedDateTime inceptio @Bind("metadata") @JSONData AlfioMetadata metadata, @Bind("ticketAccessType") TicketCategory.TicketAccessType ticketAccessType); - @Query("select * from ticket_category_with_currency where id = :id and event_id = :eventId and tc_status = 'ACTIVE'") + @Query("select * from ticket_category_with_currency where id = :id and " + CHECK_ACTIVE) TicketCategory getByIdAndActive(@Bind("id") int id, @Bind("eventId") int eventId); - @Query("select * from ticket_category_with_currency where id in (:ids) and event_id = :eventId and tc_status = 'ACTIVE'") + @Query("select * from ticket_category_with_currency where id in (:ids) and " + CHECK_ACTIVE) List getByIdsAndActive(@Bind("ids") Collection ids, @Bind("eventId") int eventId); - @Query("select * from ticket_category_with_currency where id = :id and event_id = :eventId and tc_status = 'ACTIVE'") + @Query("select * from ticket_category_with_currency where id = :id and " + CHECK_ACTIVE) Optional getOptionalByIdAndActive(@Bind("id") int id, @Bind("eventId") int eventId); @Query("select * from ticket_category_with_currency where id = :id and tc_status = 'ACTIVE'") @@ -76,10 +78,10 @@ AffectedRowCountAndKey insert(@Bind("inception") ZonedDateTime inceptio @Query("select * from ticket_category_with_currency where event_id = :eventId and category_code = :code and tc_status = 'ACTIVE'") Optional findCodeInEvent(@Bind("eventId") int eventId, @Bind("code") String code); - @Query("select count(*) from ticket_category_with_currency where event_id = :eventId and tc_status = 'ACTIVE' and bounded = false") + @Query("select count(*) from ticket_category_with_currency where " + CHECK_ACTIVE + " and bounded = false") Integer countUnboundedCategoriesByEventId(@Bind("eventId") int eventId); - @Query("select * from ticket_category_with_currency where event_id = :eventId and tc_status = 'ACTIVE' and bounded = false order by expiration desc") + @Query("select * from ticket_category_with_currency where " + CHECK_ACTIVE + " and bounded = false order by expiration desc") List findUnboundedOrderByExpirationDesc(@Bind("eventId") int eventId); @Query("select * from ticket_category_with_currency where event_id = :eventId and tc_status = 'ACTIVE' order by ordinal asc, inception asc, expiration asc, id asc") @@ -99,13 +101,13 @@ default Map findByEventIdAsMap(int eventId) { return findAllTicketCategories(eventId).stream().collect(Collectors.toMap(TicketCategory::getId, Function.identity())); } - @Query("select id, metadata from ticket_category where event_id = :eventId and tc_status = 'ACTIVE' order by ordinal asc, inception asc, expiration asc, id asc") + @Query("select id, metadata from ticket_category where " + CHECK_ACTIVE + " order by ordinal asc, inception asc, expiration asc, id asc") List findMetadataForCategoriesInEvent(@Bind("eventId") int eventId); default Map findCategoryMetadataForEventGroupByCategoryId(int eventId) { return findMetadataForCategoriesInEvent(eventId).stream() - .filter(ei -> ei.getMetadata() != null) - .collect(Collectors.toMap(EntityIdAndMetadata::getId, EntityIdAndMetadata::getMetadata)); + .filter(ei -> ei.metadata() != null) + .collect(Collectors.toMap(EntityIdAndMetadata::id, EntityIdAndMetadata::metadata)); } @Query("select count(*) from ticket_category_with_currency where event_id = :eventId and access_restricted = true") @@ -183,4 +185,7 @@ default Map findStatisticsForEventIdByCate @Query("update ticket_category set ticket_access_type = :ticketAccessType::ticket_access_type where event_id = :eventId") void updateTicketAccessTypeForEvent(@Bind("eventId") int eventId, @Bind("ticketAccessType") TicketCategory.TicketAccessType ticketAccessType); + + @Query("select count(*) from ticket_category where " + CHECK_ACTIVE) + Integer countActiveByEventId(@Bind("eventId") int eventId); } diff --git a/src/main/java/alfio/repository/TicketFieldRepository.java b/src/main/java/alfio/repository/TicketFieldRepository.java index 656747489b..ff5ccf001b 100644 --- a/src/main/java/alfio/repository/TicketFieldRepository.java +++ b/src/main/java/alfio/repository/TicketFieldRepository.java @@ -27,6 +27,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; +import java.util.Map.Entry; import java.util.function.Function; import java.util.stream.Collectors; @@ -173,8 +174,21 @@ default Map findAllValuesForTicketId(int ticketId) { default List retrieveStats(int configurationId) { TicketFieldConfiguration configuration = findById(configurationId); - Map valueStats = getValueStats(configurationId).stream().collect(Collectors.toMap(RestrictedValueStats.RestrictedValueCount::getName, RestrictedValueStats.RestrictedValueCount::getCount)); + Map valueStats = getValueStats(configurationId).stream().collect(Collectors.toMap(RestrictedValueStats.RestrictedValueCount::name, RestrictedValueStats.RestrictedValueCount::count)); int total = valueStats.values().stream().mapToInt(i -> i).sum(); + if (configuration.isCountryField()) { + // no restricted values + var descComparator = Entry.comparingByValue().reversed(); + return valueStats.entrySet().stream() + .sorted(descComparator) + .map(entry -> { + int count = entry.getValue(); + return new RestrictedValueStats(entry.getKey(), + count, + new BigDecimal(count).divide(new BigDecimal(total), 2, RoundingMode.HALF_UP).multiply(MonetaryUtil.HUNDRED).intValue() + ); + }).collect(Collectors.toList()); + } return configuration.getRestrictedValues().stream() .map(name -> { int count = valueStats.getOrDefault(name, 0); diff --git a/src/main/java/alfio/repository/TicketRepository.java b/src/main/java/alfio/repository/TicketRepository.java index 1d540f8f3a..aec894377d 100644 --- a/src/main/java/alfio/repository/TicketRepository.java +++ b/src/main/java/alfio/repository/TicketRepository.java @@ -17,12 +17,16 @@ package alfio.repository; import alfio.model.*; -import alfio.model.checkin.OnlineCheckInFullInfo; +import alfio.model.checkin.AttendeeSearchResultsCount; +import alfio.model.checkin.CheckInFullInfo; +import alfio.model.metadata.TicketMetadata; import alfio.model.metadata.TicketMetadataContainer; +import alfio.model.modification.AttendeeData; import alfio.model.poll.PollParticipant; import alfio.model.support.Array; import alfio.model.support.EnumTypeAsString; import alfio.model.support.JSONData; +import alfio.util.Json; import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; import ch.digitalfondue.npjt.QueryRepository; @@ -47,6 +51,8 @@ public interface TicketRepository { String RESET_TICKET = " TICKETS_RESERVATION_ID = null, FULL_NAME = null, EMAIL_ADDRESS = null, SPECIAL_PRICE_ID_FK = null, LOCKED_ASSIGNMENT = false, USER_LANGUAGE = null, REMINDER_SENT = false, SRC_PRICE_CTS = 0, FINAL_PRICE_CTS = 0, VAT_CTS = 0, DISCOUNT_CTS = 0, FIRST_NAME = null, LAST_NAME = null, EXT_REFERENCE = null, TAGS = array[]::text[], VAT_STATUS = null, METADATA = '{}'::jsonb "; String RELEASE_TICKET_QUERY = "update ticket set status = 'RELEASED', uuid = :newUuid, " + RESET_TICKET + " where id = :ticketId and status in('ACQUIRED', 'PENDING', 'TO_BE_PAID') and tickets_reservation_id = :reservationId and event_id = :eventId"; + String FIND_BASIC_TICKET_INFO_BY_EVENT_ID = "select t.id t_id, t.uuid t_uuid, tc.id tc_id, tc.bounded tc_bounded, t.vat_status t_vat_status from ticket t inner join ticket_category tc on t.category_id = tc.id where t.event_id = :eventId"; + String UPDATE_TICKET_PRICE = "update ticket set src_price_cts = :srcPriceCts, final_price_cts = :finalPriceCts, vat_cts = :vatCts, discount_cts = :discountCts, currency_code = :currencyCode, vat_status = :vatStatus::VAT_STATUS where event_id = :eventId and category_id = :categoryId"; //TODO: refactor, try to move the MapSqlParameterSource inside the default method! @@ -114,17 +120,27 @@ default int reserveTickets(String reservationId, TicketCategory category, String userLanguage, PriceContainer.VatStatus vatStatus, - IntFunction ticketMetadataSupplier) { + IntFunction attendeeDataSupplier) { var idx = new AtomicInteger(); var batchReserveParameters = ticketIds.stream() - .map(id -> new MapSqlParameterSource("reservationId", reservationId) - .addValue("id", id) - .addValue("categoryId", category.getId()) - .addValue("userLanguage", userLanguage) - .addValue("srcPriceCts", category.getSrcPriceCts()) - .addValue("currencyCode", category.getCurrencyCode()) - .addValue("ticketMetadata", Objects.requireNonNullElse(ticketMetadataSupplier.apply(idx.getAndIncrement()), "{}")) - .addValue("vatStatus", vatStatus.name())).toArray(MapSqlParameterSource[]::new); + .map(id -> { + var attendee = Objects.requireNonNullElse(attendeeDataSupplier.apply(idx.getAndIncrement()), AttendeeData.empty()); + String metadata = null; + if (attendee.hasMetadata()) { + metadata = Json.toJson(TicketMetadataContainer.fromMetadata(new TicketMetadata(null, null, attendee.getMetadata()))); + } + return new MapSqlParameterSource("reservationId", reservationId) + .addValue("id", id) + .addValue("categoryId", category.getId()) + .addValue("userLanguage", userLanguage) + .addValue("srcPriceCts", category.getSrcPriceCts()) + .addValue("currencyCode", category.getCurrencyCode()) + .addValue("ticketMetadata", Objects.requireNonNullElse(metadata, "{}")) + .addValue("firstName", attendee.getFirstName()) + .addValue("lastName", attendee.getLastName()) + .addValue("email", attendee.getEmail()) + .addValue("vatStatus", vatStatus.name()); + }).toArray(MapSqlParameterSource[]::new); return (int) Arrays.stream(getNamedParameterJdbcTemplate().batchUpdate(batchReserveTickets(), batchReserveParameters)) .asLongStream() .sum(); @@ -133,14 +149,15 @@ default int reserveTickets(String reservationId, @Query(type = QueryType.TEMPLATE, value = "update ticket set tickets_reservation_id = :reservationId, status = 'PENDING', category_id = :categoryId, " + "user_language = :userLanguage, src_price_cts = :srcPriceCts, currency_code = :currencyCode, metadata = :ticketMetadata::jsonb, " + - "vat_status = :vatStatus::VAT_STATUS where id = :id") + "vat_status = :vatStatus::VAT_STATUS, first_name = :firstName, last_name = :lastName, email_address = :email where id = :id") String batchReserveTickets(); @Query(type = QueryType.TEMPLATE, value = "update ticket set tickets_reservation_id = :reservationId, special_price_id_fk = :specialCodeId," + " user_language = :userLanguage, status = 'PENDING', src_price_cts = :srcPriceCts," + " currency_code = :currencyCode, vat_status = :vatStatus::VAT_STATUS," + - " metadata = :ticketMetadata::jsonb where id = :ticketId") + " metadata = :ticketMetadata::jsonb, first_name = :firstName, last_name = :lastName, email_address = :email" + + " where id = :ticketId") String batchReserveTicketsForSpecialPrice(); @Query("update ticket set tickets_reservation_id = :reservationId, special_price_id_fk = :specialCodeId," + @@ -188,11 +205,13 @@ int updateTicketPrice(@Bind("ids") List ids, @Bind("currencyCode") String currencyCode, @Bind("vatStatus") @EnumTypeAsString PriceContainer.VatStatus vatStatus); - @Query(type = QueryType.TEMPLATE, value = "update ticket set src_price_cts = :srcPriceCts, final_price_cts = :finalPriceCts," + - " vat_cts = :vatCts, discount_cts = :discountCts, currency_code = :currencyCode," + - " vat_status = :vatStatus::VAT_STATUS where event_id = :eventId and category_id = :categoryId and tickets_reservation_id = :reservationId") + @Query(type = QueryType.TEMPLATE, value = UPDATE_TICKET_PRICE + + " and tickets_reservation_id = :reservationId") String updateTicketPriceForCategoryInReservation(); + @Query(type = QueryType.TEMPLATE, value = UPDATE_TICKET_PRICE + " and uuid = :uuid") + String bulkUpdateTicketPrice(); + @Query("update ticket set tags = :tags::text[] where id in(:ids)") int updateTicketTags(@Bind("ids") List ticketIds, @Bind("tags") @Array List tags); @@ -245,6 +264,9 @@ int updateTicketPrice(@Bind("ids") List ids, @Query("update ticket set email_address = :email, full_name = :fullName, first_name = :firstName, last_name = :lastName where id = :id") int updateTicketOwnerById(@Bind("id") int id, @Bind("email") String email, @Bind("fullName") String fullName, @Bind("firstName") String firstName, @Bind("lastName") String lastName); + @Query(type = QueryType.TEMPLATE, value = "update ticket set email_address = :email, full_name = :fullName, first_name = :firstName, last_name = :lastName, metadata = :metadata::jsonb where id = :id") + String updateTicketOwnerAndMetadataById(); + @Query("update ticket set locked_assignment = :lockedAssignment where id = :id and category_id = :categoryId") int toggleTicketLocking(@Bind("id") int ticketId, @Bind("categoryId") int categoryId, @Bind("lockedAssignment") boolean locked); @@ -360,14 +382,12 @@ default void resetTickets(List ticketIds) { @Query("select count(*) from ticket where status = 'RELEASED' and event_id = :eventId") Integer countWaiting(@Bind("eventId") int eventId); - @Query("select " + - " t.id t_id, " + - " tc.id tc_id, tc.bounded tc_bounded " + - " from ticket t " + - " inner join ticket_category tc on t.category_id = tc.id "+ - " where t.event_id = :eventId and t.status = 'RELEASED' and tc.expiration <= :currentTs") + @Query(FIND_BASIC_TICKET_INFO_BY_EVENT_ID + " and t.status = 'RELEASED' and tc.expiration <= :currentTs") List findReleasedBelongingToExpiredCategories(@Bind("eventId") int eventId, @Bind("currentTs") ZonedDateTime now); + @Query(FIND_BASIC_TICKET_INFO_BY_EVENT_ID + " and t.tickets_reservation_id = :reservationId") + List findBasicTicketInfoForReservation(@Bind("eventId") int eventId, @Bind("reservationId") String reservationId); + @Query(REVERT_TO_FREE) int revertToFree(@Bind("eventId") int eventId); @@ -406,7 +426,23 @@ default void preReserveTicket(List ids) { List getCategoriesIdToPayInReservation(@Bind("reservationId") String reservationId); @Query("select * from checkin_ticket_event_and_category_info where t_uuid = :ticketUUID and e_short_name = :eventShortName and (e_format = 'ONLINE' or tc_ticket_access_type = 'ONLINE') ") - Optional getFullInfoForOnlineCheckin(@Bind("eventShortName") String eventShortName, @Bind("ticketUUID") String ticketUUID); + Optional getFullInfoForOnlineCheckin(@Bind("eventShortName") String eventShortName, @Bind("ticketUUID") String ticketUUID); + + @Query("select * from checkin_ticket_event_and_category_info where e_id = :eventId " + + "and (" + TicketSearchRepository.BASE_FILTER + " or lower(tc_name) like lower(:search)) "+ + "and (e_format = 'IN_PERSON' or tc_ticket_access_type = 'IN_PERSON') " + + "order by t_last_name, t_first_name, t_uuid limit :limit offset :offset") + List searchAttendees(@Bind("eventId") int eventId, + @Bind("search") String search, + @Bind("limit") int limit, + @Bind("offset") int offset); + + @Query("select count(*) as total, count(*) filter (where t_status = 'CHECKED_IN') as checked_in " + + "from checkin_ticket_event_and_category_info where e_id = :eventId " + + "and (" + TicketSearchRepository.BASE_FILTER + " or lower(tc_name) like lower(:search)) "+ + "and (e_format = 'IN_PERSON' or tc_ticket_access_type = 'IN_PERSON') ") + AttendeeSearchResultsCount countSearchResults(@Bind("eventId") int eventId, + @Bind("search") String search); @Query("update ticket set status = 'CHECKED_IN', locked_assignment = true where uuid = :uuid and event_id = :eventId and status = 'ACQUIRED'") int performCheckIn(@Bind("uuid") String ticketUUID, @Bind("eventId") int eventId); @@ -447,4 +483,12 @@ int applySubscriptionToTicketsInReservation(@Bind("reservationId") String reserv @Query(FIND_TICKETS_IN_RESERVATION) List findTicketsInReservationWithMetadata(@Bind("reservationId") String reservationId); + @Query("select t.id from ticket t" + + " join event e on t.event_id = e.id" + + " join tickets_reservation tr on t.tickets_reservation_id = tr.id" + + " join ticket_field_value tfv on t.id = tfv.ticket_id_fk" + + " where e.short_name = :eventPublicIdentifier and tr.id = :reservationId") + List findTicketsWithAdditionalData(@Bind("reservationId") String reservationId, + @Bind("eventPublicIdentifier") String eventPublicIdentifier); + } diff --git a/src/main/java/alfio/repository/TicketReservationRepository.java b/src/main/java/alfio/repository/TicketReservationRepository.java index d95a2880ae..301131c17f 100644 --- a/src/main/java/alfio/repository/TicketReservationRepository.java +++ b/src/main/java/alfio/repository/TicketReservationRepository.java @@ -17,6 +17,7 @@ package alfio.repository; import alfio.model.*; +import alfio.model.support.JSONData; import alfio.model.support.UserIdAndOrganizationId; import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; @@ -147,9 +148,6 @@ int postponePayment(@Bind("reservationId") String reservationId, @Bind("status") @Query("update tickets_reservation set invoice_number = :invoiceNumber where id = :reservationId") int setInvoiceNumber(@Bind("reservationId") String reservationId, @Bind("invoiceNumber") String invoiceNumber); - @Query("select count(*) from tickets_reservation where invoice_number is not null and event_id_fk = :eventId") - Integer countInvoices(@Bind("eventId") int eventId); - @Query("update tickets_reservation set vat_status = :vatStatus, src_price_cts = :srcPriceCts, " + " final_price_cts = :finalPriceCts, vat_cts = :vatCts, discount_cts = :discountCts, currency_code = :currencyCode, " + @@ -235,6 +233,16 @@ int updateTicketReservationWithValidation(@Bind("reservationId") String reservat " from tickets_reservation where id = :id") TicketReservationAdditionalInfo getAdditionalInfo(@Bind("id") String reservationId); + @Query("select metadata from tickets_reservation where id = :id") + @JSONData + ReservationMetadata getMetadata(@Bind("id") String reservationId); + + @Query("select metadata->'finalized' = 'true' as finalized from tickets_reservation where id = :id") + Boolean checkIfFinalized(@Bind("id") String reservationId); + + @Query("update tickets_reservation set metadata = :metadata::jsonb where id = :id") + int setMetadata(@Bind("id") String reservationId, @Bind("metadata") @JSONData ReservationMetadata metadata); + @Query("update tickets_reservation set validated_for_overview = :validated where id = :reservationId") int updateValidationStatus(@Bind("reservationId") String reservationId, @Bind("validated") boolean validated); diff --git a/src/main/java/alfio/repository/TicketSearchRepository.java b/src/main/java/alfio/repository/TicketSearchRepository.java index 6e00ddbe93..a71602595e 100644 --- a/src/main/java/alfio/repository/TicketSearchRepository.java +++ b/src/main/java/alfio/repository/TicketSearchRepository.java @@ -16,11 +16,13 @@ */ package alfio.repository; +import alfio.model.ReservationPaymentDetail; import alfio.model.TicketReservation; import alfio.model.TicketReservationWithTransaction; import alfio.model.TicketWithReservationAndTransaction; import alfio.model.poll.PollParticipant; import alfio.model.support.Array; +import alfio.model.transaction.Transaction; import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; import ch.digitalfondue.npjt.QueryRepository; @@ -31,8 +33,12 @@ @QueryRepository public interface TicketSearchRepository { - String APPLY_FILTER = " (:search is null or (lower(tr_id) like lower(:search) or lower(t_uuid) like lower(:search) or lower(t_full_name) like lower(:search) or lower(t_first_name) like lower(:search) or lower(t_last_name) like lower(:search) or lower(t_email_address) like lower(:search) or " + - " lower(tr_full_name) like lower(:search) or lower(tr_first_name) like lower(:search) or lower(tr_last_name) like lower(:search) or lower(tr_email_address) like lower(:search) or lower(tr_customer_reference) like lower(:search) or lower(promo_code) like lower(:search) or lower(special_price_token) like lower(:search))) "; + + String BASE_FILTER = ":search is null or (lower(tr_id) like lower(:search) or lower(t_uuid) like lower(:search) or lower(t_full_name) like lower(:search) or lower(t_first_name) like lower(:search) or lower(t_last_name) like lower(:search) or lower(t_email_address) like lower(:search) or " + + " lower(tr_full_name) like lower(:search) or lower(tr_first_name) like lower(:search) or lower(tr_last_name) like lower(:search) or lower(tr_email_address) like lower(:search) or lower(tr_customer_reference) like lower(:search) " + + " or (tr_invoice_number is not null and lower(tr_invoice_number) like lower(:search)) )"; + + String APPLY_FILTER = " (" + BASE_FILTER + " or lower(promo_code) like lower(:search) or lower(special_price_token) like lower(:search)) "; String APPLY_FILTER_SUBSCRIPTION = " (:search is null or (lower(tr_id) like lower(:search) or lower(s_id::text) like lower(:search) or lower(s_first_name) like lower(:search) or lower(s_last_name) like lower(:search) or lower(s_email_address) like lower(:search) " + " or lower(tr_first_name) like lower(:search) or lower(tr_last_name) like lower(:search) or lower(tr_email_address) like lower(:search) or lower(tr_customer_reference) like lower(:search) or lower(promo_code) like lower(:search) )) "; @@ -41,6 +47,8 @@ public interface TicketSearchRepository { String FIND_ALL_CONFIRMED_TICKETS_FOR_EVENT = "select * from reservation_and_ticket_and_tx where t_id is not null and t_status in ('ACQUIRED', 'TO_BE_PAID', 'CHECKED_IN') and t_event_id = :eventId and " + APPLY_FILTER; + String FIND_ALL_PAYMENTS_FOR_EVENT = "select * from reservation_and_ticket_and_tx where tr_status in (:reservationStatus) and tr_payment_method in (:paymentMethods) and t_id is not null and t_status in ('ACQUIRED', 'TO_BE_PAID', 'CHECKED_IN') and t_event_id = :eventId and " + APPLY_FILTER; + String FIND_ALL_TICKETS_INCLUDING_NEW = "select * from reservation_and_ticket_and_tx where tr_event_id = :eventId and tr_id is not null and tr_status in (:status) and " + APPLY_FILTER; String FIND_ALL_SUBSCRIPTION_INCLUDING_NEW = "select * from reservation_and_subscription_and_tx where s_descriptor_id = :subscriptionDescriptorId::uuid and tr_id is not null and tr_status in (:status) and " + APPLY_FILTER_SUBSCRIPTION; @@ -89,6 +97,22 @@ List findReservationsForEvent(@Bind("eventId") int eventId, @Bind("search") String search, @Bind("status") List toFilter); + @Query("select distinct tr_id, tr_first_name, tr_last_name, tr_email_address, tr_payment_method, bt_price_cts, bt_currency, bt_t_timestamp, bt_metadata ->> '"+ Transaction.NOTES_KEY + "'" + + " as bt_notes, tr_invoice_number from (" + FIND_ALL_PAYMENTS_FOR_EVENT + ") as d_tbl order by bt_t_timestamp desc nulls last limit :pageSize offset :page") + List findAllPaymentsForEvent(@Bind("eventId") int eventId, + @Bind("page") int page, + @Bind("pageSize") int pageSize, + @Bind("search") String search, + @Bind("reservationStatus") List toFilter, + @Bind("paymentMethods") List paymentMethods); + + @Query("select distinct tr_id, tr_first_name, tr_last_name, tr_email_address, tr_payment_method, bt_price_cts, bt_currency, bt_t_timestamp, bt_metadata ->> '"+ Transaction.NOTES_KEY + "'" + + " as bt_notes, tr_invoice_number from (" + FIND_ALL_PAYMENTS_FOR_EVENT + ") as d_tbl order by bt_t_timestamp desc nulls last") + List findAllEventPaymentsForExport(@Bind("eventId") int eventId, + @Bind("search") String search, + @Bind("reservationStatus") List toFilter, + @Bind("paymentMethods") List paymentMethods); + @Query("select distinct "+RESERVATION_FIELDS+" from (" + FIND_ALL_SUBSCRIPTION_INCLUDING_NEW + ") as d_tbl order by tr_confirmation_ts desc nulls last, tr_validity limit :pageSize offset :page") List findReservationsForSubscription(@Bind("subscriptionDescriptorId") UUID subscriptionDescriptorId, @Bind("page") int page, @@ -118,6 +142,12 @@ Integer countReservationsForSubscription(@Bind("subscriptionDescriptorId") UUID @Bind("search") String search, @Bind("status") List toFilter); + @Query("select count(distinct tr_id) from (" + FIND_ALL_PAYMENTS_FOR_EVENT +") as d_tbl") + Integer countConfirmedPaymentsForEvent(@Bind("eventId") int eventId, + @Bind("search") String search, + @Bind("reservationStatus") List toFilter, + @Bind("paymentMethods") List paymentMethods); + @Query("select * from reservation_and_ticket_and_tx where tr_event_id = :eventId and tickets_count > 0 and tr_id in (:reservationIds)") List loadAllReservationsWithTickets(@Bind("eventId") int eventId, @Bind("reservationIds") Collection reservationIds); diff --git a/src/main/java/alfio/repository/TransactionRepository.java b/src/main/java/alfio/repository/TransactionRepository.java index 021a93ab03..2fefe9a809 100644 --- a/src/main/java/alfio/repository/TransactionRepository.java +++ b/src/main/java/alfio/repository/TransactionRepository.java @@ -122,4 +122,9 @@ int updateFees(@Bind("transactionId") String transactionId, @Query("update b_transaction set status = 'INVALID' where id = :id") int invalidateById(@Bind("id") int id); + + @Query("update b_transaction set metadata = :metadata::jsonb, t_timestamp = :timestamp where id = :id") + int updateDetailsById(@Bind("id") int id, + @Bind("metadata") @JSONData Map metadata, + @Bind("timestamp") ZonedDateTime timestamp); } diff --git a/src/main/java/alfio/repository/audit/ScanAuditRepository.java b/src/main/java/alfio/repository/audit/ScanAuditRepository.java index eca3813687..fce7a42d31 100644 --- a/src/main/java/alfio/repository/audit/ScanAuditRepository.java +++ b/src/main/java/alfio/repository/audit/ScanAuditRepository.java @@ -17,6 +17,7 @@ package alfio.repository.audit; import alfio.manager.support.CheckInStatus; +import alfio.model.api.v1.admin.CheckInLogEntry; import alfio.model.audit.ScanAudit; import ch.digitalfondue.npjt.Bind; import ch.digitalfondue.npjt.Query; @@ -38,4 +39,12 @@ Integer insert(@Bind("ticketUuid") String ticketUuid, @Query("select * from scan_audit where event_id_fk = :eventId") List findAllForEvent(@Bind("eventId") int eventId); + @Query("select t.uuid t_uuid, jsonb_build_object('firstName', t.first_name, 'lastName', t.last_name, 'email', t.email_address, 'metadata', coalesce(t.metadata::jsonb#>'{metadataMap, general, attributes}', '{}')) attendee_data, jsonb_agg(jsonb_build_object('ticketUuid', sa.ticket_uuid, 'scanTimestamp', sa.scan_ts, 'username', sa.username, 'checkInStatus', sa.check_in_status, 'operation', sa.operation)) scans from ticket t\n" + + " join event e on t.event_id = e.id" + + " join scan_audit sa on e.id = sa.event_id_fk and t.uuid = sa.ticket_uuid" + + " where e.id = :eventId" + + " and t.status = 'CHECKED_IN'" + + " group by 1,2") + List loadEntries(@Bind("eventId") int eventId); + } \ No newline at end of file diff --git a/src/main/java/alfio/repository/system/AdminJobQueueRepository.java b/src/main/java/alfio/repository/system/AdminJobQueueRepository.java index 919eeba362..38d285ce11 100644 --- a/src/main/java/alfio/repository/system/AdminJobQueueRepository.java +++ b/src/main/java/alfio/repository/system/AdminJobQueueRepository.java @@ -17,7 +17,6 @@ package alfio.repository.system; import alfio.manager.system.AdminJobExecutor.JobName; -import alfio.model.support.EnumTypeAsString; import alfio.model.support.JSONData; import alfio.model.system.AdminJobSchedule; import ch.digitalfondue.npjt.Bind; @@ -49,12 +48,13 @@ int updateSchedule(@Bind("id") long id, int scheduleRetry(@Bind("id") long id, @Bind("requestTs") ZonedDateTime requestTs); - @Query("insert into admin_job_queue(job_name, request_ts, metadata, status, attempts)" + - " values(:jobName, :requestTs, to_json(:metadata::json), 'SCHEDULED', 1)" + + @Query("insert into admin_job_queue(job_name, request_ts, metadata, status, attempts, allow_duplicates)" + + " values(:jobName, :requestTs, to_json(:metadata::json), 'SCHEDULED', 1, :allowDuplicates)" + " on conflict do nothing") int schedule(@Bind("jobName") JobName jobName, @Bind("requestTs") ZonedDateTime requestTimestamp, - @Bind("metadata") @JSONData Map metadata); + @Bind("metadata") @JSONData Map metadata, + @Bind("allowDuplicates") String allowDuplicates); @Query("delete from admin_job_queue where status in (:status) and request_ts <= :requestTs") int removePastSchedules(@Bind("requestTs") ZonedDateTime requestTs, @Bind("status") Set statuses); diff --git a/src/main/java/alfio/repository/system/ConfigurationRepository.java b/src/main/java/alfio/repository/system/ConfigurationRepository.java index 3184abdbc1..e1bf4968d6 100644 --- a/src/main/java/alfio/repository/system/ConfigurationRepository.java +++ b/src/main/java/alfio/repository/system/ConfigurationRepository.java @@ -24,7 +24,7 @@ import ch.digitalfondue.npjt.Query; import ch.digitalfondue.npjt.QueryRepository; import ch.digitalfondue.npjt.ConstructorAnnotationRowMapper.Column; -import lombok.Getter; +import ch.digitalfondue.npjt.QueryType; import java.util.Collection; import java.util.List; @@ -57,11 +57,40 @@ public interface ConfigurationRepository { @Query("SELECT ticket_category_id_fk, c_value FROM configuration_ticket_category where organization_id_fk = :organizationId and event_id_fk = :eventId and c_key = :key") List findAllCategoriesAndValueWith(@Bind("organizationId") int organizationId, @Bind("eventId") int eventId, @Bind("key") String key); - @Getter + @Query("select ticket_category_id_fk from configuration_ticket_category where ticket_category_id_fk in (:categories) and c_key = :flagName and c_value = :flagValue") + List getCategoriesWithFlag(@Bind("categories") List categoriesIds, + @Bind("flagName") String flagName, + @Bind("flagValue") String flagValue); + + @Query("insert into configuration_event (c_key, c_value, description, event_id_fk, organization_id_fk)" + + " select c_key, c_value, description, :targetEventId, :targetOrgId from configuration_event where event_id_fk = :srcEventId and organization_id_fk = :srcOrgId") + int copyEventConfiguration(@Bind("targetEventId") int targetEventId, + @Bind("targetOrgId") int targetOrgId, + @Bind("srcEventId") int srcEventId, + @Bind("srcOrgId") int srcOrgId); + + @Query("insert into configuration_ticket_category (c_key, c_value, description, event_id_fk, organization_id_fk, ticket_category_id_fk)" + + " select c_key, c_value, description, :targetEventId, :targetOrgId, :targetCategoryId from configuration_ticket_category where event_id_fk = :srcEventId and organization_id_fk = :srcOrgId and ticket_category_id_fk = :srcCategoryId") + int copyCategoryConfiguration(@Bind("targetEventId") int targetEventId, + @Bind("targetOrgId") int targetOrgId, + @Bind("targetCategoryId") int targetCategoryId, + @Bind("srcEventId") int srcEventId, + @Bind("srcOrgId") int srcOrgId, + @Bind("srcCategoryId") int srcCategoryId); + class CategoryAndValue { + final int ticketCategoryId; final String value; + public int getTicketCategoryId() { + return ticketCategoryId; + } + + public String getValue() { + return value; + } + public CategoryAndValue(@Column("ticket_category_id_fk") int ticketCategoryId, @Column("c_value") String value) { this.ticketCategoryId = ticketCategoryId; this.value = value; diff --git a/src/main/java/alfio/repository/user/OrganizationRepository.java b/src/main/java/alfio/repository/user/OrganizationRepository.java index 2997d9b498..ef1a5a7524 100644 --- a/src/main/java/alfio/repository/user/OrganizationRepository.java +++ b/src/main/java/alfio/repository/user/OrganizationRepository.java @@ -71,6 +71,4 @@ int update(@Bind("id") int id, "(select * from organization where 'ROLE_ADMIN' in (select role from ba_user inner join authority on ba_user.username = authority.username where ba_user.username = :username) and id = :orgId)") Optional findOrganizationForUser(@Bind("username") String username, @Bind("orgId") int orgId); - @Query("delete from organization where id in(:organizationIds) and id not in (select distinct(org_id) from j_user_organization where org_id in(:organizationIds))") - int deleteOrganizationsIfEmpty(@Bind("organizationIds") List organizationIds); } diff --git a/src/main/java/alfio/repository/user/UserRepository.java b/src/main/java/alfio/repository/user/UserRepository.java index 1f5bf51955..2bcf4f5102 100644 --- a/src/main/java/alfio/repository/user/UserRepository.java +++ b/src/main/java/alfio/repository/user/UserRepository.java @@ -106,8 +106,8 @@ int update(@Bind("id") int id, @Bind("username") String username, @Bind("firstNa @Query("delete from ba_user where id = :id") int deleteUser(@Bind("id") int id); - @Query("select id from ba_user where user_type = :type and enabled = true and user_creation_time < :date") - List findUsersToDeleteOlderThan(@Bind("date") Date date, @Bind("type") User.Type type); + @Query("select id from ba_user where user_type in (:types) and enabled = true and user_creation_time < :date") + List findUsersToDeleteOlderThan(@Bind("date") Date date, @Bind("types") Collection types); @Query("delete from authority where username = (select username from ba_user where id = :id)") int deleteUserFromAuthority(@Bind("id") int id); diff --git a/src/main/java/alfio/repository/user/join/UserOrganizationRepository.java b/src/main/java/alfio/repository/user/join/UserOrganizationRepository.java index e26aedf7a0..ebc11d1e07 100644 --- a/src/main/java/alfio/repository/user/join/UserOrganizationRepository.java +++ b/src/main/java/alfio/repository/user/join/UserOrganizationRepository.java @@ -52,4 +52,6 @@ public interface UserOrganizationRepository { @Query("delete from j_user_organization where user_id = :userId and org_id in (:organizationIds)") int removeOrganizationUserLinks(@Bind("userId") int userId, @Bind("organizationIds") Collection organizationIds); + @Query("delete from j_user_organization where org_id = :organizationId") + int cleanupOrganization(@Bind("organizationId") int organizationId); } diff --git a/src/main/java/alfio/util/DefaultExceptionHandler.java b/src/main/java/alfio/util/DefaultExceptionHandler.java index 66c3f10fc8..f57355d165 100644 --- a/src/main/java/alfio/util/DefaultExceptionHandler.java +++ b/src/main/java/alfio/util/DefaultExceptionHandler.java @@ -16,10 +16,14 @@ */ package alfio.util; -import lombok.extern.log4j.Log4j2; -@Log4j2 +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class DefaultExceptionHandler implements Thread.UncaughtExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class); + @Override public void uncaughtException(Thread t, Throwable e) { log.error("uncaught Exception", e); diff --git a/src/main/java/alfio/util/EventUtil.java b/src/main/java/alfio/util/EventUtil.java index efd2728ad4..e9f9c8ab1e 100644 --- a/src/main/java/alfio/util/EventUtil.java +++ b/src/main/java/alfio/util/EventUtil.java @@ -33,9 +33,12 @@ import biweekly.property.Method; import biweekly.property.Organizer; import biweekly.property.Status; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.RegExUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.commons.lang3.StringUtils; +import org.flywaydb.core.api.MigrationVersion; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.web.util.UriComponentsBuilder; @@ -53,13 +56,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static alfio.model.EventCheckInInfo.VERSION_FOR_CODE_CASE_INSENSITIVE; import static alfio.model.TicketFieldConfiguration.Context.ATTENDEE; import static alfio.model.system.ConfigurationKeys.*; import static java.time.temporal.ChronoField.*; -@Log4j2 public final class EventUtil { + private static final Logger log = LoggerFactory.getLogger(EventUtil.class); + private EventUtil() {} private static final DateTimeFormatter JSON_TIME_FORMATTER = new DateTimeFormatterBuilder() @@ -207,7 +212,7 @@ public static String getGoogleCalendarURL(Event event, TicketCategory category, .queryParam("ctz", event.getTimeZone()) .queryParam("text", event.getDisplayName()) .queryParam("location", event.getLocation()) - .queryParam("details", description) + .queryParam("details", StringUtils.abbreviate(description, 1024)) .toUriString(); } @@ -238,7 +243,7 @@ public static Function public static Optional findMatchingLink(ZoneId eventZoneId, OnlineConfiguration categoryConfiguration, OnlineConfiguration eventConfiguration) { return firstMatchingCallLink(eventZoneId, categoryConfiguration, eventConfiguration) - .map(JoinLink::getLink); + .map(JoinLink::link); } public static Optional firstMatchingCallLink(ZoneId eventZoneId, OnlineConfiguration categoryConfiguration, OnlineConfiguration eventConfiguration) { @@ -250,8 +255,8 @@ public static Optional firstMatchingCallLink(ZoneId eventZoneId, Onlin private static Optional firstMatchingCallLink(OnlineConfiguration onlineConfiguration, ZoneId zoneId, ZonedDateTime now) { return Optional.ofNullable(onlineConfiguration).stream() .flatMap(configuration -> configuration.getCallLinks().stream()) - .sorted(Comparator.comparing(JoinLink::getValidFrom).reversed()) - .filter(joinLink -> now.isBefore(joinLink.getValidTo().atZone(zoneId)) && now.plusSeconds(1).isAfter(joinLink.getValidFrom().atZone(zoneId))) + .sorted(Comparator.comparing(JoinLink::validFrom).reversed()) + .filter(joinLink -> now.isBefore(joinLink.validTo().atZone(zoneId)) && now.plusSeconds(1).isAfter(joinLink.validFrom().atZone(zoneId))) .findFirst(); } @@ -286,4 +291,9 @@ public static String getLocalizedMessage(Map messagesByLang, Str return messagesByLang.values().stream().findFirst().orElseThrow(); } + + public static boolean supportsCaseInsensitiveQRCode(String version) { + return version != null + && MigrationVersion.fromVersion(version).compareTo(MigrationVersion.fromVersion(VERSION_FOR_CODE_CASE_INSENSITIVE)) >= 0; + } } diff --git a/src/main/java/alfio/util/ExportUtils.java b/src/main/java/alfio/util/ExportUtils.java index 457c4fc520..244a0790d5 100644 --- a/src/main/java/alfio/util/ExportUtils.java +++ b/src/main/java/alfio/util/ExportUtils.java @@ -18,13 +18,16 @@ import ch.digitalfondue.basicxlsx.Cell; import ch.digitalfondue.basicxlsx.StreamingWorkbook; +import ch.digitalfondue.basicxlsx.Style; import com.opencsv.CSVWriter; +import org.apache.commons.lang3.StringUtils; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Arrays; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,16 +37,31 @@ public class ExportUtils { private static final int[] BOM_MARKERS = new int[] {0xEF, 0xBB, 0xBF}; + private ExportUtils() {} + public static void exportExcel(String fileName, String sheetName, String[] header, Stream data, HttpServletResponse response) throws IOException { + exportExcel(fileName, response, workbook -> addSheetToWorkbook(sheetName, header, data, workbook, workbook.defineStyle().font().bold(true).build())); + } + + public static void exportExcel(String fileName, + HttpServletResponse response, + Consumer workbookConsumer) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); - try (ServletOutputStream out = response.getOutputStream(); StreamingWorkbook workbook = new StreamingWorkbook(out)) { - var boldFont = workbook.defineStyle().font().bold(true).build(); + workbookConsumer.accept(workbook); + } + } + public static void addSheetToWorkbook(String sheetName, + String[] header, + Stream data, + StreamingWorkbook workbook, + Style headerStyle) { + try { var headerRow = StreamingWorkbook.row(Arrays.stream(header) - .map(v -> Cell.cell(v).withStyle(boldFont)) + .map(v -> Cell.cell(v).withStyle(headerStyle)) .collect(Collectors.toList())); var dataStream = data @@ -51,7 +69,21 @@ public static void exportExcel(String fileName, String sheetName, String[] heade .map(StreamingWorkbook::row); workbook.withSheet(sheetName, Stream.concat(Stream.of(headerRow), dataStream)); + + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + // https://owasp.org/www-community/attacks/CSV_Injection + private static String escapeFormulaChar(String s) { + var trimmed = StringUtils.trimToEmpty(s); + // tab and carriage return are removed by the trimming + var res = trimmed; + if (StringUtils.startsWithAny(trimmed, "=", "+", "-", "@")) { + res = "\t" + trimmed; // http://georgemauer.net/2017/10/07/csv-injection.html starting with a tab seems to be enough? } + return res; } public static void exportCsv(String fileName, String[] header, Stream data, HttpServletResponse response) throws IOException { @@ -63,7 +95,14 @@ public static void exportCsv(String fileName, String[] header, Stream out.write(marker); } writer.writeNext(header); - data.forEachOrdered(writer::writeNext); + data.forEachOrdered(d -> { + var copy = Arrays.copyOf(d, d.length); + for (var i = 0; i < copy.length; i++) { + var res = copy[i]; + copy[i] = escapeFormulaChar(res); + } + writer.writeNext(copy); + }); writer.flush(); out.flush(); } diff --git a/src/main/java/alfio/util/FileUtil.java b/src/main/java/alfio/util/FileUtil.java index fa9be41b90..db7b5f04e1 100644 --- a/src/main/java/alfio/util/FileUtil.java +++ b/src/main/java/alfio/util/FileUtil.java @@ -17,6 +17,7 @@ package alfio.util; import alfio.model.BillingDocument; +import org.springframework.http.MediaType; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -41,7 +42,7 @@ public static boolean sendPdf(byte[] res, HttpServletResponse response, String e public static void sendHeaders(HttpServletResponse response, String eventName, String reservationId, BillingDocument billingDocument) { response.setHeader("Content-Disposition", "attachment; filename=\"" + getBillingDocumentFileName(eventName, reservationId, billingDocument) + "\""); - response.setContentType("application/pdf"); + response.setContentType(MediaType.APPLICATION_PDF_VALUE); } public static String getBillingDocumentFileName(String eventShortName, String reservationId, BillingDocument document) { diff --git a/src/main/java/alfio/util/HttpUtils.java b/src/main/java/alfio/util/HttpUtils.java index 5a033dced4..d8cdb1cdd2 100644 --- a/src/main/java/alfio/util/HttpUtils.java +++ b/src/main/java/alfio/util/HttpUtils.java @@ -35,6 +35,7 @@ private HttpUtils() { public static final String CONTENT_TYPE = "Content-Type"; public static final String APPLICATION_JSON = "application/json"; + public static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8"; public static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; public static final String MULTIPART_FORM_DATA = "multipart/form-data"; public static final String AUTHORIZATION = "Authorization"; @@ -132,7 +133,7 @@ public enum TYPE { class PartsIterator implements Iterator { - private Iterator iter; + private final Iterator iter; private InputStream currentFileInput; private boolean done; diff --git a/src/main/java/alfio/util/ImageUtil.java b/src/main/java/alfio/util/ImageUtil.java index 826a57d3e3..80241849af 100644 --- a/src/main/java/alfio/util/ImageUtil.java +++ b/src/main/java/alfio/util/ImageUtil.java @@ -26,7 +26,8 @@ import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import javax.imageio.ImageIO; @@ -39,9 +40,10 @@ import static org.apache.commons.lang3.StringUtils.center; import static org.apache.commons.lang3.StringUtils.truncate; -@Log4j2 public final class ImageUtil { + private static final Logger log = LoggerFactory.getLogger(ImageUtil.class); + private static final Cache FONT_CACHE = Caffeine.newBuilder() .removalListener((String key, File value, RemovalCause cause) -> { if(value != null) { diff --git a/src/main/java/alfio/util/ItalianTaxIdValidator.java b/src/main/java/alfio/util/ItalianTaxIdValidator.java index d62fca504d..b153716a15 100644 --- a/src/main/java/alfio/util/ItalianTaxIdValidator.java +++ b/src/main/java/alfio/util/ItalianTaxIdValidator.java @@ -16,8 +16,6 @@ */ package alfio.util; -import lombok.AllArgsConstructor; -import lombok.experimental.UtilityClass; import org.apache.commons.lang3.StringUtils; import java.util.*; @@ -25,8 +23,7 @@ import static java.util.Map.entry; import static org.apache.commons.lang3.StringUtils.*; -@UtilityClass -public class ItalianTaxIdValidator { +public final class ItalianTaxIdValidator { private static final char[] CONTROL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); private static final String VOWELS = "AEIOU"; private static final int COMPANY_TAX_ID_LENGTH = 11; @@ -69,6 +66,9 @@ public class ItalianTaxIdValidator { entry('9', new EvenOddValueContainer(9,21)) ); + private ItalianTaxIdValidator() { + } + public static boolean validateFiscalCode(String fiscalCode) { var code = StringUtils.upperCase(trimToNull(fiscalCode)); int length = length(code); @@ -149,6 +149,9 @@ public static boolean validateVatId(String vatId) { int sumEven = 0; int sumOdd = 0; var chars = nr.toCharArray(); + if (chars.length != COMPANY_TAX_ID_LENGTH) { + return false; + } for (int i=0; i < 10; i++) { int val = Character.getNumericValue(chars[i]); if((i + 1) % 2 == 0) { @@ -165,19 +168,16 @@ public static boolean validateVatId(String vatId) { return controlDigit == Character.getNumericValue(chars[10]); } - @AllArgsConstructor - private static class EvenOddValueContainer { - private final int evenValue; - private final int oddValue; + + private record EvenOddValueContainer(int evenValue, int oddValue) { private int getValue(int index) { return (index + 1) % 2 == 0 ? evenValue : oddValue; } } - @AllArgsConstructor - private static class FiscalCodeParts { - private final List consonants; - private final List vowels; + + private record FiscalCodeParts(List consonants, + List vowels) { } } diff --git a/src/main/java/alfio/util/LocaleUtil.java b/src/main/java/alfio/util/LocaleUtil.java index d59b5e8afb..3b55c9e26d 100644 --- a/src/main/java/alfio/util/LocaleUtil.java +++ b/src/main/java/alfio/util/LocaleUtil.java @@ -21,11 +21,13 @@ import alfio.model.Ticket; import org.apache.commons.lang3.StringUtils; +import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -66,6 +68,13 @@ public static ZonedDateTime atZone(ZonedDateTime in, ZoneId zone) { return null; } + public static ZonedDateTime atZone(LocalDateTime in, ZoneId zone) { + if(in != null) { + return in.atZone(Objects.requireNonNull(zone)); + } + return null; + } + public static Map formatDate(ZonedDateTime date, Map datePatterns) { if(date == null) { return null; diff --git a/src/main/java/alfio/util/MiscUtils.java b/src/main/java/alfio/util/MiscUtils.java new file mode 100644 index 0000000000..6647447187 --- /dev/null +++ b/src/main/java/alfio/util/MiscUtils.java @@ -0,0 +1,32 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.util; + +import java.util.List; + +public class MiscUtils { + private MiscUtils() { + } + + public static T getAtIndexOrNull(List elements, int index) { + if (elements == null || index < 0 || index >= elements.size()) { + return null; + } + return elements.get(index); + } + +} diff --git a/src/main/java/alfio/util/MustacheCustomTag.java b/src/main/java/alfio/util/MustacheCustomTag.java index 063484030d..b83e89e55e 100644 --- a/src/main/java/alfio/util/MustacheCustomTag.java +++ b/src/main/java/alfio/util/MustacheCustomTag.java @@ -17,8 +17,8 @@ package alfio.util; import alfio.controller.api.support.TicketHelper; +import alfio.model.subscription.SubscriptionDescriptor; import com.samskivert.mustache.Mustache; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.text.StringEscapeUtils; @@ -26,10 +26,14 @@ import org.commonmark.ext.gfm.tables.TablesExtension; import org.commonmark.node.Link; import org.commonmark.node.Node; +import org.commonmark.node.Text; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.AttributeProvider; import org.commonmark.renderer.html.HtmlRenderer; import org.commonmark.renderer.text.TextContentRenderer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; import org.springframework.security.web.util.UrlUtils; import java.time.ZonedDateTime; @@ -57,9 +61,12 @@ *
  • optional: locale:YOUR_LOCALE you can define the locale
  • * */ -@Log4j2 public class MustacheCustomTag { + private static final Logger log = LoggerFactory.getLogger(MustacheCustomTag.class); + + public static final String SUBSCRIPTION_DESCRIPTOR_ATTRIBUTE = "subscriptionDescriptor"; + private MustacheCustomTag() {} private static final Pattern ARG_PATTERN = Pattern.compile("\\[(.*?)]"); @@ -76,6 +83,25 @@ private MustacheCustomTag() {} } }; + /** + * {{#render-markdown}}[markdown][.html|.text]{{/render-markdown}} + * The string must end with either .html or .text, otherwise Markdown won't be parsed + * e.g. + * {{#render-markdown}}(link)[description].html{{/render-markdown}} will produce HTML output + * {{#render-markdown}}(link)[description].text{{/render-markdown}} will produce text/plain output + */ + static final Mustache.Lambda RENDER_MARKDOWN = (frag, out) -> { + String execution = frag.execute().strip(); + if(execution.endsWith(".html")) { + // Markdown renderer will take care of escaping all dangerous content + out.write(renderToHtmlCommonmark(StringUtils.removeEnd(execution, ".html"), null)); + } else if(execution.endsWith(".text")) { + out.write(renderToTextCommonmark(StringUtils.removeEnd(execution, ".text"))); + } else { + out.write(execution); + } + }; + static final Mustache.Lambda COUNTRY_NAME = (frag, out) -> { String execution = frag.execute().trim(); String code = substring(execution, 0, 2); @@ -97,11 +123,10 @@ static String translateCountryCode(String code, Locale locale) { * prefix is optional, unless a suffix is needed. */ static final Function ADDITIONAL_FIELD_VALUE = obj -> (frag, out) -> { - if( !(obj instanceof Map) || ((Map)obj).isEmpty()) { + if( !(obj instanceof Map fieldNamesAndValues) || ((Map)obj).isEmpty()) { log.warn("map not found or empty. Skipping additionalFieldValue tag"); return; } - Map fieldNamesAndValues = (Map) obj; String execution = frag.execute().trim(); Matcher matcher = ARG_PATTERN.matcher(execution); List args = new ArrayList<>(); @@ -120,6 +145,40 @@ static String translateCountryCode(String code, Locale locale) { } }; + static Mustache.Lambda subscriptionDescriptionGenerator(MessageSource messageSource, Map model, Locale locale) { + return (frag, out) -> { + var subscriptionDescriptor = (SubscriptionDescriptor) Objects.requireNonNull(model.get(SUBSCRIPTION_DESCRIPTOR_ATTRIBUTE)); + var usageType = messageSource.getMessage("subscription.usage-type." + subscriptionDescriptor.getUsageType(), null, locale); + switch (subscriptionDescriptor.getValidityType()) { + case STANDARD: + var standardParams = new Object[] { + subscriptionDescriptor.getValidityUnits(), + messageSource.getMessage("subscription.time-unit." + subscriptionDescriptor.getValidityTimeUnit(), null, locale), + usageType + }; + out.write(messageSource.getMessage("subscription.detail.validity.STANDARD.description", standardParams, locale)); + break; + case NOT_SET: + var notSetParams = new Object[] { + subscriptionDescriptor.getMaxEntries(), + messageSource.getMessage("subscription.usage-type." + subscriptionDescriptor.getUsageType(), null, locale), + usageType + }; + out.write(messageSource.getMessage("subscription.detail.validity.NOT_SET.description", notSetParams, locale)); + break; + case CUSTOM: + var formatter = DateTimeFormatter.ofPattern(messageSource.getMessage("common.event.date-format", null, locale)); + out.write(messageSource.getMessage("subscription.detail.validity.CUSTOM.from", null, locale)); + out.write(" " + formatter.format(subscriptionDescriptor.getValidityFrom())); + out.write(messageSource.getMessage("subscription.detail.validity.CUSTOM.to", null, locale)); + out.write(" " + formatter.format(subscriptionDescriptor.getValidityTo())); + out.write(" - " + usageType); + break; + } + }; + } + + private static Pair> parseParams(String r) { int indexLocale = r.indexOf(LOCALE_LABEL); @@ -138,27 +197,59 @@ private static Pair> parseParams(String r) { private static final List COMMONMARK_EXTENSIONS = List.of(TablesExtension.create()); private static final Parser COMMONMARK_PARSER = Parser.builder().extensions(COMMONMARK_EXTENSIONS).build(); - private static final HtmlRenderer COMMONMARK_RENDERER = HtmlRenderer.builder().extensions(COMMONMARK_EXTENSIONS).attributeProviderFactory((ctx) -> new TargetBlankProvider()).build(); + private static final HtmlRenderer COMMONMARK_RENDERER = HtmlRenderer.builder().extensions(COMMONMARK_EXTENSIONS).attributeProviderFactory(ctx -> new TargetBlankProvider()).build(); private static final TextContentRenderer COMMONMARK_TEXT_RENDERER = TextContentRenderer.builder().extensions(COMMONMARK_EXTENSIONS).build(); + private static final ThreadLocal A11Y_NEW_TAB_LABEL = new ThreadLocal<>(); //Open in a new window if the link contains an absolute url private static class TargetBlankProvider implements AttributeProvider { @Override public void setAttributes(Node node, String tagName, Map attributes) { - if (node instanceof Link) { - Link l = (Link) node; + if (node instanceof Link l) { String destination = StringUtils.trimToEmpty(l.getDestination()); + var scheme = getScheme(destination); + scheme.ifPresent(resolvedScheme -> { + if (!Set.of("http", "https").contains(resolvedScheme)) { + log.info("User tried to set an url with scheme {}, only http/https are accepted, href has been removed", resolvedScheme); + attributes.remove("href"); + } + }); if (UrlUtils.isAbsoluteUrl(destination)) { + // accept only http or https protocols if we have an absolute link, else we override with an empty string attributes.put("target", "_blank"); attributes.put("rel", "nofollow noopener noreferrer"); + var newTabLabel = A11Y_NEW_TAB_LABEL.get(); + if (newTabLabel != null) { + attributes.put("aria-label", ((Text)node.getFirstChild()).getLiteral() + " " + newTabLabel); + } } } } } - public static String renderToHtmlCommonmarkEscaped(String input) { - Node document = COMMONMARK_PARSER.parse(StringEscapeUtils.escapeHtml4(input)); - return COMMONMARK_RENDERER.render(document); + return renderToHtmlCommonmarkEscaped(input, null); + } + + /** + * return lowercase scheme if present + */ + private static Optional getScheme(String uri) { + var s = StringUtils.trimToEmpty(uri).toLowerCase(Locale.ROOT); + return s.indexOf(':') >= 0 ? Optional.of(StringUtils.substringBefore(s, ':')) : Optional.empty(); + } + + public static String renderToHtmlCommonmarkEscaped(String input, String localizedNewWindowLabel) { + return renderToHtmlCommonmark(StringEscapeUtils.escapeHtml4(input), localizedNewWindowLabel); + } + + private static String renderToHtmlCommonmark(String input, String localizedNewWindowLabel) { + try { + A11Y_NEW_TAB_LABEL.set(localizedNewWindowLabel); + Node document = COMMONMARK_PARSER.parse(input); + return COMMONMARK_RENDERER.render(document); + } finally { + A11Y_NEW_TAB_LABEL.remove(); + } } public static String renderToTextCommonmark(String input) { diff --git a/src/main/java/alfio/util/ObjectDiffUtil.java b/src/main/java/alfio/util/ObjectDiffUtil.java index d31d07a61f..a214ea5d89 100644 --- a/src/main/java/alfio/util/ObjectDiffUtil.java +++ b/src/main/java/alfio/util/ObjectDiffUtil.java @@ -17,8 +17,6 @@ package alfio.util; import alfio.model.Ticket; -import lombok.AllArgsConstructor; -import lombok.Getter; import org.apache.commons.lang3.builder.CompareToBuilder; import org.springframework.beans.BeanUtils; import org.springframework.util.ReflectionUtils; @@ -83,14 +81,35 @@ public static List diff(T before, T after, Class objectType) { return diffUntyped(beforeAsMap, afterAsMap, "/", ""); } - @AllArgsConstructor - @Getter public static class Change implements Comparable { private final String propertyName; private final State state; private final Object oldValue; private final Object newValue; + public String getPropertyName() { + return propertyName; + } + + public State getState() { + return state; + } + + public Object getOldValue() { + return oldValue; + } + + public Object getNewValue() { + return newValue; + } + + public Change(String propertyName, State state, Object oldValue, Object newValue) { + this.propertyName = propertyName; + this.state = state; + this.oldValue = oldValue; + this.newValue = newValue; + } + @Override public int compareTo(Change change) { return new CompareToBuilder() diff --git a/src/main/java/alfio/util/PinGenerator.java b/src/main/java/alfio/util/PinGenerator.java index a7075d177c..da3d5c6866 100644 --- a/src/main/java/alfio/util/PinGenerator.java +++ b/src/main/java/alfio/util/PinGenerator.java @@ -16,7 +16,6 @@ */ package alfio.util; -import lombok.experimental.UtilityClass; import org.apache.commons.lang3.StringUtils; import org.springframework.util.Assert; @@ -24,13 +23,14 @@ import java.util.Objects; import java.util.regex.Pattern; -@UtilityClass -public class PinGenerator { +public final class PinGenerator { private static final String ALLOWED_CHARS = "ACDEFGHJKLMNPQRTUVWXY34679"; private static final Pattern VALIDATION_PATTERN = Pattern.compile("^["+ALLOWED_CHARS+"]+$"); private static final int PIN_LENGTH = 6; + private PinGenerator() { + } public static String uuidToPin(String uuid, int pinLength) { var src = new BigInteger(uuid.replace("-", "").substring(0, pinLength+1), 16); diff --git a/src/main/java/alfio/util/RenderedTemplate.java b/src/main/java/alfio/util/RenderedTemplate.java index 35baa75fe8..ed5da7bc91 100644 --- a/src/main/java/alfio/util/RenderedTemplate.java +++ b/src/main/java/alfio/util/RenderedTemplate.java @@ -16,16 +16,25 @@ */ package alfio.util; -import lombok.Getter; - import java.util.Map; -@Getter public class RenderedTemplate { private final String textPart; private final String htmlPart; private final Map srcModel; + public Map getSrcModel() { + return srcModel; + } + + public String getHtmlPart() { + return htmlPart; + } + + public String getTextPart() { + return textPart; + } + private RenderedTemplate(String textPart, String htmlPart, Map model) { this.textPart = textPart; this.htmlPart = htmlPart; diff --git a/src/main/java/alfio/util/RequestUtils.java b/src/main/java/alfio/util/RequestUtils.java index 446de50bd4..936b7ee3b1 100644 --- a/src/main/java/alfio/util/RequestUtils.java +++ b/src/main/java/alfio/util/RequestUtils.java @@ -18,9 +18,9 @@ import alfio.model.ContentLanguage; import alfio.model.Event; -import lombok.experimental.UtilityClass; -import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.IteratorUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.web.context.request.ServletWebRequest; @@ -29,18 +29,18 @@ import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; import java.security.Principal; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Optional; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; -@Log4j2 -@UtilityClass -public class RequestUtils { +public final class RequestUtils { + + private RequestUtils() { + } + + private static final Logger log = LoggerFactory.getLogger(RequestUtils.class); public static Optional readRequest(HttpServletRequest request) { try (ServletInputStream is = request.getInputStream()){ @@ -58,6 +58,14 @@ public static boolean isSocialMediaShareUA(String ua) { } + public static Locale getMatchingLocale(ServletWebRequest request, List allowedLanguages) { + var l = requireNonNull(request.getNativeRequest(HttpServletRequest.class)).getLocales(); + List locales = l != null ? IteratorUtils.toList(l.asIterator()) : Collections.emptyList(); + var selectedLocale = locales.stream().map(Locale::getLanguage).filter(allowedLanguages::contains).findFirst() + .orElseGet(() -> allowedLanguages.stream().findFirst().orElseThrow()); + return LocaleUtil.forLanguageTag(selectedLocale); + } + /** * From a given request, return the best locale for the user * @@ -66,19 +74,26 @@ public static boolean isSocialMediaShareUA(String ua) { * @return */ public static Locale getMatchingLocale(ServletWebRequest request, Event event) { - var allowedLanguages = event.getContentLanguages().stream().map(ContentLanguage::getLanguage).collect(Collectors.toSet()); - var l = requireNonNull(request.getNativeRequest(HttpServletRequest.class)).getLocales(); - List locales = l != null ? IteratorUtils.toList(l.asIterator()) : Collections.emptyList(); - var selectedLocale = locales.stream().map(Locale::getLanguage).filter(allowedLanguages::contains).findFirst() - .orElseGet(() -> event.getContentLanguages().stream().findFirst().orElseThrow().getLanguage()); - return LocaleUtil.forLanguageTag(selectedLocale); + var allowedLanguages = event.getContentLanguages().stream().map(ContentLanguage::getLanguage).collect(Collectors.toList()); + return getMatchingLocale(request, allowedLanguages); } public static boolean isAdmin(Principal principal) { if (principal instanceof Authentication) { - return ((Authentication) principal).getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .anyMatch("ROLE_ADMIN"::equals); + return hasRole((Authentication) principal, "ROLE_ADMIN"); + } + return false; + } + + private static boolean hasRole(Authentication principal, String role) { + return principal.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .anyMatch(role::equals); + } + + public static boolean isSystemApiKey(Principal principal) { + if (principal instanceof Authentication) { + return hasRole((Authentication)principal, "ROLE_SYSTEM_API_CLIENT"); } return false; } diff --git a/src/main/java/alfio/util/ReservationUtil.java b/src/main/java/alfio/util/ReservationUtil.java index 5337971011..7a2c9a955c 100644 --- a/src/main/java/alfio/util/ReservationUtil.java +++ b/src/main/java/alfio/util/ReservationUtil.java @@ -22,11 +22,13 @@ import alfio.manager.PromoCodeRequestManager; import alfio.manager.TicketReservationManager; import alfio.manager.support.response.ValidatedResponse; +import alfio.manager.system.ConfigurationManager; import alfio.model.*; import alfio.model.modification.ASReservationWithOptionalCodeModification; import alfio.model.modification.AdditionalServiceReservationModification; -import alfio.model.modification.TicketReservationModification; +import alfio.model.modification.ReservationRequest; import alfio.model.modification.TicketReservationWithOptionalCodeModification; +import alfio.repository.TicketCategoryRepository; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.springframework.validation.BindingResult; @@ -34,21 +36,17 @@ import java.math.BigDecimal; import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; +import java.util.*; import static java.util.Collections.emptyList; import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; public class ReservationUtil { private ReservationUtil() { } - public static Optional checkPromoCode(ReservationCreate createRequest, + public static Optional checkPromoCode(ReservationCreate createRequest, Event event, PromoCodeRequestManager promoCodeRequestManager, BindingResult bindingResult) { @@ -68,7 +66,7 @@ public static Optional checkPromoCode(ReservationCreate createRequest, } - public static Optional, List>> validateCreateRequest(ReservationCreate request, + public static Optional, List>> validateCreateRequest(ReservationCreate request, Errors bindingResult, TicketReservationManager tickReservationManager, EventManager eventManager, @@ -84,10 +82,9 @@ public static Optional, return Optional.empty(); } - List> maxTicketsByTicketReservation = selected(request.getTickets()).stream() - .map(r -> Pair.of(r, tickReservationManager.maxAmountOfTicketsForCategory(event, r.getTicketCategoryId(), validatedPromoCodeDiscount))) - .collect(toList()); - Optional> error = maxTicketsByTicketReservation.stream() + List> maxTicketsByTicketReservation = selected(request.getTickets()).stream() + .map(r -> Pair.of((ReservationRequest) r, tickReservationManager.maxAmountOfTicketsForCategory(event, r.getTicketCategoryId(), validatedPromoCodeDiscount))).toList(); + Optional> error = maxTicketsByTicketReservation.stream() .filter(p -> p.getKey().getQuantity() > p.getValue()) .findAny(); @@ -96,7 +93,7 @@ public static Optional, return Optional.empty(); } - final List categories = selected(request.getTickets()); + final var categories = selected(request.getTickets()); final List additionalServices = selectedAdditionalServices(request.getAdditionalServices()); final boolean validCategorySelection = categories.stream().allMatch(c -> { @@ -127,16 +124,16 @@ public static Optional, // final ZonedDateTime now = event.now(ClockProvider.clock()); maxTicketsByTicketReservation.forEach(pair -> validateCategory(bindingResult, tickReservationManager, eventManager, event, pair.getRight(), res, specialCode, now, pair.getLeft())); - return bindingResult.hasErrors() ? Optional.empty() : Optional.of(Pair.of(res, additionalServices.stream().map(as -> new ASReservationWithOptionalCodeModification(as, specialCode)).collect(Collectors.toList()))); + return bindingResult.hasErrors() ? Optional.empty() : Optional.of(Pair.of(res, additionalServices.stream().map(as -> new ASReservationWithOptionalCodeModification(as, specialCode)).toList())); } - private static int ticketSelectionCount(List tickets) { - return selected(tickets).stream().mapToInt(TicketReservationModification::getQuantity).sum(); + private static int ticketSelectionCount(List tickets) { + return selected(tickets).stream().mapToInt(ReservationRequest::getQuantity).sum(); } - private static void validateCategory(Errors bindingResult, TicketReservationManager tickReservationManager, EventManager eventManager, + private static void validateCategory(Errors bindingResult, TicketReservationManager tickReservationManager, EventManager eventManager, Event event, int maxAmountOfTicket, List res, - Optional specialCode, ZonedDateTime now, TicketReservationModification r) { + Optional specialCode, ZonedDateTime now, T r) { TicketCategory tc = eventManager.getTicketCategoryById(r.getTicketCategoryId(), event.getId()); SaleableTicketCategory ticketCategory = new SaleableTicketCategory(tc, now, event, tickReservationManager.countAvailableTickets(event, tc), maxAmountOfTicket, null); @@ -148,12 +145,12 @@ private static void validateCategory(Errors bindingResult, TicketReservationMana res.add(new TicketReservationWithOptionalCodeModification(r, ticketCategory.isAccessRestricted() ? specialCode : Optional.empty())); } - private static List selected(List reservation) { + private static List selected(List reservation) { return ofNullable(reservation) .orElse(emptyList()) .stream() .filter(e -> e != null && e.getQuantity() != null && e.getTicketCategoryId() != null && e.getQuantity() > 0) - .collect(toList()); + .toList(); } private static List selectedAdditionalServices(List additionalServices) { @@ -161,6 +158,51 @@ private static List selectedAdditional .orElse(emptyList()) .stream() .filter(e -> e != null && e.getQuantity() != null && e.getAdditionalServiceId() != null && e.getQuantity() > 0) - .collect(toList()); + .toList(); + } + + public static boolean hasPrivacyPolicy(PurchaseContext event) { + return StringUtils.isNotBlank(event.getPrivacyPolicyLinkOrNull()); + } + + public static String ticketUpdateUrl(Event event, Ticket ticket, ConfigurationManager configurationManager) { + return configurationManager.baseUrl(event) + "/event/" + event.getShortName() + "/ticket/" + ticket.getUuid() + "/update?lang=" + ticket.getUserLanguage(); + } + + public static String reservationUrl(String baseUrl, String reservationId, + PurchaseContext purchaseContext, + String userLanguage, + String additionalParams) { + var cleanParams = StringUtils.trimToNull(additionalParams); + return StringUtils.removeEnd(baseUrl, "/") + + "/" + purchaseContext.getType() + + "/" + purchaseContext.getPublicIdentifier() + + "/reservation/" + reservationId + + "?lang="+userLanguage + + (cleanParams != null ? "&" + cleanParams : ""); + } + public static String reservationUrl(String baseUrl, String reservationId, PurchaseContext purchaseContext, String userLanguage) { + return reservationUrl(baseUrl, reservationId, purchaseContext, userLanguage, null); + } + + public static String reservationUrl(TicketReservation reservation, PurchaseContext purchaseContext, ConfigurationManager configurationManager) { + return reservationUrl(configurationManager.baseUrl(purchaseContext), reservation.getId(), purchaseContext, reservation.getUserLanguage()); + } + + public static List collectTicketsWithCategory(Map> ticketsByCategory, TicketCategoryRepository ticketCategoryRepository) { + final List ticketsWithCategory; + if(!ticketsByCategory.isEmpty()) { + ticketsWithCategory = ticketCategoryRepository.findByIds(ticketsByCategory.keySet()) + .stream() + .flatMap(tc -> ticketsByCategory.get(tc.getId()).stream().map(t -> new TicketWithCategory(t, tc))) + .toList(); + } else { + ticketsWithCategory = Collections.emptyList(); + } + return ticketsWithCategory; + } + + public static Locale getReservationLocale(TicketReservation reservation) { + return StringUtils.isEmpty(reservation.getUserLanguage()) ? Locale.ENGLISH : LocaleUtil.forLanguageTag(reservation.getUserLanguage()); } } diff --git a/src/main/java/alfio/util/SqlUtils.java b/src/main/java/alfio/util/SqlUtils.java index c049e38c8c..de58032b3e 100644 --- a/src/main/java/alfio/util/SqlUtils.java +++ b/src/main/java/alfio/util/SqlUtils.java @@ -16,7 +16,6 @@ */ package alfio.util; -import lombok.experimental.UtilityClass; import org.postgresql.util.PSQLException; import org.postgresql.util.ServerErrorMessage; import org.springframework.jdbc.UncategorizedSQLException; @@ -25,8 +24,12 @@ import java.time.ZonedDateTime; import java.util.Optional; -@UtilityClass -public class SqlUtils { + +public final class SqlUtils { + + private SqlUtils() { + } + public static Optional findServerError(UncategorizedSQLException exception) { for (var throwable : exception.getSQLException()) { if(throwable instanceof PSQLException && ((PSQLException)throwable).getServerErrorMessage() != null) { diff --git a/src/main/java/alfio/util/TemplateManager.java b/src/main/java/alfio/util/TemplateManager.java index 58341ebaf3..a5a1720d93 100644 --- a/src/main/java/alfio/util/TemplateManager.java +++ b/src/main/java/alfio/util/TemplateManager.java @@ -18,6 +18,7 @@ import alfio.manager.UploadedResourceManager; import alfio.manager.i18n.MessageSourceManager; +import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; import alfio.model.Event; import alfio.model.PurchaseContext; @@ -25,8 +26,9 @@ import com.samskivert.mustache.Mustache; import com.samskivert.mustache.Mustache.Compiler; import com.samskivert.mustache.Template; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; @@ -44,19 +46,20 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static alfio.util.MustacheCustomTag.ADDITIONAL_FIELD_VALUE; -import static alfio.util.MustacheCustomTag.COUNTRY_NAME; +import static alfio.util.MustacheCustomTag.*; /** * For hiding the ugliness :) * */ -@Log4j2 public class TemplateManager { + private static final Logger log = LoggerFactory.getLogger(TemplateManager.class); + public static final String METADATA_ATTRIBUTES_KEY = "metadata-attributes"; public static final String ADDITIONAL_FIELDS_KEY = "additional-fields"; public static final String VAT_TRANSLATION_TEMPLATE_KEY = "vatTranslation"; + public static final String MAIL_FOOTER = "mailFooter"; private final MessageSourceManager messageSourceManager; @@ -103,16 +106,22 @@ private static String dateFormatter(Object o) { private RenderedTemplate renderMultipartTemplate(PurchaseContext purchaseContext, TemplateResource templateResource, Map model, Locale locale) { var enrichedModel = modelEnricher(model, purchaseContext, locale); + var options = configurationManager.getFor(EnumSet.of(ConfigurationKeys.MAIL_FOOTER, ConfigurationKeys.ENABLE_HTML_EMAILS), purchaseContext.getConfigurationLevel()); + var mailFooter = options.get(ConfigurationKeys.MAIL_FOOTER); + enrichedModel.put("hasMailFooter", mailFooter.isPresent()); + enrichedModel.put(MAIL_FOOTER, mailFooter.getValueOrNull()); var isMultipart = templateResource.isMultipart(); var textRender = render(new ClassPathResource(templateResource.classPath()), enrichedModel, locale, purchaseContext, isMultipart ? TemplateOutput.TEXT : templateResource.getTemplateOutput()); - boolean htmlEnabled = configurationManager.getFor(ConfigurationKeys.ENABLE_HTML_EMAILS, purchaseContext.getConfigurationLevel()).getValueAsBooleanOrDefault(); - - var htmlRender = isMultipart && htmlEnabled ? - render(new ClassPathResource(templateResource.htmlClassPath()), enrichedModel, locale, purchaseContext, TemplateOutput.HTML) : - null; - + boolean htmlEnabled = options.get(ConfigurationKeys.ENABLE_HTML_EMAILS).getValueAsBooleanOrDefault(); + + String htmlRender = null; + + if(isMultipart && htmlEnabled) { + htmlRender = render(new ClassPathResource(templateResource.htmlClassPath()), enrichedModel, locale, purchaseContext, TemplateOutput.HTML); + } + return RenderedTemplate.multipart(textRender, htmlRender, model); } @@ -147,17 +156,29 @@ private Map modelEnricher(Map model, PurchaseCon private String render(Resource resource, Map model, Locale locale, PurchaseContext purchaseContext, TemplateOutput templateOutput) { try { + var messageSource = messageSourceManager.getMessageSourceFor(purchaseContext); + var configuration = configurationManager.getFor(EnumSet.of(ConfigurationKeys.USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL, ConfigurationKeys.ENABLE_WALLET, ConfigurationKeys.ENABLE_PASS), ConfigurationLevel.purchaseContext(purchaseContext)); + boolean usePartnerCode = Objects.requireNonNull(configuration.get(ConfigurationKeys.USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL)) + .getValueAsBooleanOrDefault(); ModelAndView mv = new ModelAndView(); mv.getModelMap().addAllAttributes(model); mv.addObject("format-date", MustacheCustomTag.FORMAT_DATE); mv.addObject("country-name", COUNTRY_NAME); + mv.addObject("render-markdown", RENDER_MARKDOWN); mv.addObject("additional-field-value", ADDITIONAL_FIELD_VALUE.apply(model.get(ADDITIONAL_FIELDS_KEY))); mv.addObject("metadata-value", ADDITIONAL_FIELD_VALUE.apply(model.get(METADATA_ATTRIBUTES_KEY))); - mv.addObject("i18n", new CustomLocalizationMessageInterceptor(locale, messageSourceManager.getMessageSourceFor(purchaseContext)).createTranslator()); + mv.addObject("i18n", new CustomLocalizationMessageInterceptor(locale, messageSource).createTranslator()); + mv.addObject("discountCodeDescription", messageSource.getMessage("show-event.promo-code-type." + (usePartnerCode ? "partner" : "promotional"), null, locale)); + mv.addObject("subscriptionDescription", MustacheCustomTag.subscriptionDescriptionGenerator(messageSource, model, locale)); var updatedModel = mv.getModel(); updatedModel.putIfAbsent("custom-header-text", ""); updatedModel.putIfAbsent("custom-body-text", ""); updatedModel.putIfAbsent("custom-footer-text", ""); + boolean googleWalletEnabled = configuration.get(ConfigurationKeys.ENABLE_WALLET).getValueAsBooleanOrDefault(); + boolean appleWalletEnabled = configuration.get(ConfigurationKeys.ENABLE_PASS).getValueAsBooleanOrDefault(); + updatedModel.putIfAbsent("googleWalletEnabled", googleWalletEnabled); + updatedModel.putIfAbsent("appleWalletEnabled", appleWalletEnabled); + updatedModel.putIfAbsent("walletEnabled", googleWalletEnabled || appleWalletEnabled); return compile(resource, templateOutput).execute(mv.getModel()); } catch (Exception e) { log.error("TemplateManager: got exception while generating a template", e); diff --git a/src/main/java/alfio/util/TemplateResource.java b/src/main/java/alfio/util/TemplateResource.java index 4630b7c95b..af9ec810d5 100644 --- a/src/main/java/alfio/util/TemplateResource.java +++ b/src/main/java/alfio/util/TemplateResource.java @@ -17,16 +17,20 @@ package alfio.util; import alfio.model.*; +import alfio.model.PurchaseContext.PurchaseContextType; +import alfio.model.api.v1.admin.subscription.SubscriptionConfiguration; +import alfio.model.metadata.SubscriptionMetadata; import alfio.model.modification.SendCodeModification; +import alfio.model.subscription.Subscription; +import alfio.model.subscription.SubscriptionDescriptor; +import alfio.model.subscription.SubscriptionDescriptor.SubscriptionValidityType; import alfio.model.transaction.PaymentMethod; import alfio.model.transaction.PaymentProxy; import alfio.model.user.Organization; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.experimental.Delegate; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.http.MediaType; import java.math.BigDecimal; import java.time.ZoneId; @@ -36,6 +40,7 @@ import java.util.stream.Collectors; import static alfio.util.ImageUtil.createQRCode; +import static alfio.util.MustacheCustomTag.SUBSCRIPTION_DESCRIPTOR_ATTRIBUTE; import static alfio.util.TemplateManager.ADDITIONAL_FIELDS_KEY; import static alfio.util.TemplateManager.METADATA_ATTRIBUTES_KEY; import static org.springframework.http.MediaType.APPLICATION_PDF_VALUE; @@ -49,61 +54,61 @@ public enum TemplateResource { CONFIRMATION_EMAIL_FOR_ORGANIZER("/alfio/templates/confirmation-email-for-organizer", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.HTML) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, SEND_RESERVED_CODE("/alfio/templates/send-reserved-code-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareModelForSendReservedCode(organization, event, new SendCodeModification("CODE", "Firstname Lastname", "email@email.tld", "en"), "http://your-domain.tld/event-page", "Promotional"); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareModelForSendReservedCode(organization, (Event) event, new SendCodeModification("CODE", "Firstname Lastname", "email@email.tld", "en"), "http://your-domain.tld/event-page", "Promotional"); } }, CONFIRMATION_EMAIL("/alfio/templates/confirmation-email", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, CONFIRMATION_EMAIL_SUBSCRIPTION("/alfio/templates/confirmation-email-subscription", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, OFFLINE_RESERVATION_EXPIRED_EMAIL("/alfio/templates/offline-reservation-expired-email-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, CHARGE_ATTEMPT_FAILED_EMAIL("/alfio/templates/charge-failed-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForChargeFailed(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForChargeFailed(organization, (Event) event); } }, CHARGE_ATTEMPT_FAILED_EMAIL_FOR_ORGANIZER("/alfio/templates/charge-failed-organizer-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForChargeFailed(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForChargeFailed(organization, (Event) event); } }, CREDIT_NOTE_ISSUED_EMAIL("/alfio/templates/credit-note-issued-email-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, OFFLINE_RESERVATION_EXPIRING_EMAIL_FOR_ORGANIZER("/alfio/templates/offline-reservation-expiring-email-for-organizer", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleModelForOfflineReservationExpiringEmailForOrganizer(event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleModelForOfflineReservationExpiringEmailForOrganizer((Event) event); } }, OFFLINE_PAYMENT_MATCHES_FOUND("/alfio/templates/offline-payment-matches-found-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { return Map.of( "matchingCount", 3, "eventName", event.getDisplayName(), @@ -118,27 +123,28 @@ public Map prepareSampleModel(Organization organization, Event e }, REMINDER_EMAIL("/alfio/templates/reminder-email-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, REMINDER_TICKET_ADDITIONAL_INFO("/alfio/templates/reminder-ticket-additional-info.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareModelForReminderTicketAdditionalInfo(organization, event, sampleTicket(event.getZoneId()), "http://your-domain.tld/ticket-url"); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareModelForReminderTicketAdditionalInfo(organization, (Event) event, sampleTicket(event.getZoneId()), "http://your-domain.tld/ticket-url"); } }, REMINDER_TICKETS_ASSIGNMENT_EMAIL("/alfio/templates/reminder-tickets-assignment-email-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return prepareSampleDataForConfirmationEmail(organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return prepareSampleDataForConfirmationEmail(organization, (Event) event); } }, TICKET_EMAIL("/alfio/templates/ticket-email", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { + public Map prepareSampleModel(Organization organization, PurchaseContext purchaseContext, Optional imageData) { + Event event = (Event) purchaseContext; var now = event.now(ClockProvider.clock()); TicketCategory ticketCategory = new TicketCategory(0, now, now, 42, "Ticket", false, TicketCategory.Status.ACTIVE, event.getId(), false, 1000, null, null, null, null, null, "CHF", 0, null, TicketCategory.TicketAccessType.INHERIT); return buildModelForTicketEmail(organization, event, sampleTicketReservation(event.getZoneId()), "http://your-domain.tld", "http://your-domain.tld/ticket-url", "http://your-domain.tld/calendar-url", sampleTicket(event.getZoneId()), ticketCategory, Map.of()); @@ -147,7 +153,8 @@ public Map prepareSampleModel(Organization organization, Event e TICKET_EMAIL_FOR_ONLINE_EVENT("/alfio/templates/ticket-email-online", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { + public Map prepareSampleModel(Organization organization, PurchaseContext purchaseContext, Optional imageData) { + Event event = (Event) purchaseContext; var now = event.now(ClockProvider.clock()); TicketCategory ticketCategory = new TicketCategory(0, now, now, 42, "Ticket", false, TicketCategory.Status.ACTIVE, event.getId(), false, 1000, null, null, null, null, null, "CHF", 0, null, TicketCategory.TicketAccessType.INHERIT); return buildModelForTicketEmail(organization, event, sampleTicketReservation(event.getZoneId()), "http://your-domain.tld", "http://your-domain.tld/ticket-url", "http://your-domain.tld/calendar-url", sampleTicket(event.getZoneId()), ticketCategory, Map.of("onlineCheckInUrl", "https://your-domain.tld/check-in", "prerequisites", "An internet connection is required to join the event")); @@ -156,29 +163,30 @@ public Map prepareSampleModel(Organization organization, Event e TICKET_HAS_CHANGED_OWNER("/alfio/templates/ticket-has-changed-owner-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return buildModelForTicketHasChangedOwner(organization, event, sampleTicket(event.getZoneId()), sampleTicket("NewFirstname", "NewLastname", "newemail@email.tld", event.getZoneId()), "http://your-domain.tld/ticket-url"); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return buildModelForTicketHasChangedOwner(organization, (Event) event, sampleTicket(event.getZoneId()), sampleTicket("NewFirstname", "NewLastname", "newemail@email.tld", event.getZoneId()), "http://your-domain.tld/ticket-url"); } }, TICKET_HAS_BEEN_CANCELLED("/alfio/templates/ticket-has-been-cancelled-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return buildModelForTicketHasBeenCancelled(organization, event, sampleTicket(event.getZoneId())); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return buildModelForTicketHasBeenCancelled(organization, (Event) event, sampleTicket(event.getZoneId())); } }, TICKET_HAS_BEEN_CANCELLED_ADMIN("/alfio/templates/ticket-has-been-cancelled-admin-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return buildModelForTicketHasBeenCancelledAdmin(organization, event, sampleTicket(event.getZoneId()), "Category", Collections.emptyList(), asi -> Optional.empty()); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return buildModelForTicketHasBeenCancelledAdmin(organization, (Event) event, sampleTicket(event.getZoneId()), "Category", Collections.emptyList(), asi -> Optional.empty()); } }, TICKET_PDF("/alfio/templates/ticket.ms", APPLICATION_PDF_VALUE, TemplateManager.TemplateOutput.HTML) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { + public Map prepareSampleModel(Organization organization, PurchaseContext purchaseContext, Optional imageData) { + Event event = (Event) purchaseContext; var now = event.now(ClockProvider.clock()); TicketCategory ticketCategory = new TicketCategory(0, now, now, 42, "Ticket", false, TicketCategory.Status.ACTIVE, event.getId(), false, 1000, null, null, null, null, null, "CHF", 0, null, TicketCategory.TicketAccessType.INHERIT); var ticketWithMetadata = TicketWithMetadataAttributes.build(sampleTicket(event.getZoneId()), null); @@ -187,40 +195,80 @@ public Map prepareSampleModel(Organization organization, Event e }, RECEIPT_PDF("/alfio/templates/receipt.ms", APPLICATION_PDF_VALUE, TemplateManager.TemplateOutput.HTML) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return sampleBillingDocument(imageData, organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return sampleBillingDocument(imageData, organization, (Event) event); } }, INVOICE_PDF("/alfio/templates/invoice.ms", APPLICATION_PDF_VALUE, TemplateManager.TemplateOutput.HTML) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return sampleBillingDocument(imageData, organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return sampleBillingDocument(imageData, organization, (Event) event); } }, CREDIT_NOTE_PDF("/alfio/templates/credit-note.ms", APPLICATION_PDF_VALUE, TemplateManager.TemplateOutput.HTML) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return sampleBillingDocument(imageData, organization, event); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return sampleBillingDocument(imageData, organization, (Event) event); + } + }, + SUBSCRIPTION_PDF("/alfio/templates/subscription.ms", APPLICATION_PDF_VALUE, TemplateManager.TemplateOutput.HTML, PurchaseContextType.subscription) { + @Override + public Map prepareSampleModel(Organization organization, PurchaseContext purchaseContext, Optional imageData) { + var subscriptionDescriptor = (SubscriptionDescriptor) purchaseContext; + var zoneId = subscriptionDescriptor.getZoneId(); + var subscription = new Subscription(UUID.randomUUID(), + "firstName", + "lastName", + "email@example.org", + subscriptionDescriptor.getId(), + RESERVATION_ID_VALUE, + organization.getId(), + ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), + ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), + 100, + 0, + "CHF", + AllocationStatus.ACQUIRED, + 1, + ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), + ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)).plusDays(1), + ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), + subscriptionDescriptor.getTimeZone() + ); + var subscriptionMetadata = new SubscriptionMetadata(Map.of("key", "value"), SubscriptionConfiguration.defaultConfiguration()); + return buildModelForSubscriptionPDF(subscription, subscriptionDescriptor, organization, subscriptionMetadata, imageData, RESERVATION_ID_VALUE, Locale.ENGLISH, sampleTicketReservation(zoneId)); } }, WAITING_QUEUE_JOINED("/alfio/templates/waiting-queue-joined.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { - return buildModelForWaitingQueueJoined(organization, event, new CustomerName("Firstname Lastname", "Firstname", "Lastname", event.mustUseFirstAndLastName())); + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { + return buildModelForWaitingQueueJoined(organization, (Event) event, new CustomerName("Firstname Lastname", "Firstname", "Lastname", event.mustUseFirstAndLastName())); } }, WAITING_QUEUE_RESERVATION_EMAIL("/alfio/templates/waiting-queue-reservation-email-txt.ms", TEXT_PLAIN_VALUE, TemplateManager.TemplateOutput.TEXT) { @Override - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { + public Map prepareSampleModel(Organization organization, PurchaseContext purchaseContext, Optional imageData) { + Event event = (Event) purchaseContext; var clock = ClockProvider.clock().withZone(event.getZoneId()); WaitingQueueSubscription subscription = new WaitingQueueSubscription(0, ZonedDateTime.now(clock), event.getId(), "ACQUIRED", "Firstname Lastname", "Firstname", "Lastname", - "email@email.tld", "597e7e7b-c514-4dcb-be8c-46cf7fe2c36e", "en", null, WaitingQueueSubscription.Type.PRE_SALES); + "email@email.tld", RESERVATION_ID_VALUE, "en", null, WaitingQueueSubscription.Type.PRE_SALES); return buildModelForWaitingQueueReservationEmail(organization, event, subscription, "http://your-domain.tld/reservation-url", ZonedDateTime.now(clock)); } - }; + }, + CUSTOM_MESSAGE("/alfio/templates/custom-message", TemplateResource.MULTIPART_ALTERNATIVE_MIMETYPE, TemplateManager.TemplateOutput.TEXT) { + @Override + public Map prepareSampleModel(Organization organization, PurchaseContext purchaseContext, Optional imageData) { + var now = purchaseContext.now(ClockProvider.clock()); + var event = (Event) purchaseContext; + TicketCategory ticketCategory = new TicketCategory(0, now, now, 42, "Ticket", false, TicketCategory.Status.ACTIVE, event.getId(), false, 1000, null, null, null, null, null, "CHF", 0, null, TicketCategory.TicketAccessType.INHERIT); + var model = buildModelForTicketEmail(organization, event, sampleTicketReservation(event.getZoneId()), "http://your-domain.tld", "http://your-domain.tld/ticket-url", "http://your-domain.tld/calendar-url", sampleTicket(event.getZoneId()), ticketCategory, Map.of()); + model.put("message", "This is your message"); + return model; + } + },; public static final String MULTIPART_ALTERNATIVE_MIMETYPE = "multipart/alternative"; @@ -228,6 +276,8 @@ public Map prepareSampleModel(Organization organization, Event e private static final String HTML_TEMPLATE_SUFFIX = "-html.ms"; private static final String TICKET_KEY = "ticket"; + private static final String RESERVATION_ID = "reservationId"; + private static final String RESERVATION_ID_VALUE = "597e7e7b-c514-4dcb-be8c-46cf7fe2c36e"; private final String classPathUrl; @@ -235,12 +285,20 @@ public Map prepareSampleModel(Organization organization, Event e private final boolean overridable; private final String renderedContentType; private final TemplateManager.TemplateOutput templateOutput; + /** + * PurchaseContextType used for preview + */ + private final PurchaseContextType purchaseContextType; TemplateResource(String classPathUrl, String renderedContentType, TemplateManager.TemplateOutput templateOutput) { + this(classPathUrl, renderedContentType, templateOutput, PurchaseContextType.event); + } + TemplateResource(String classPathUrl, String renderedContentType, TemplateManager.TemplateOutput templateOutput, PurchaseContextType purchaseContextType) { this.classPathUrl = classPathUrl; this.overridable = true; this.renderedContentType = renderedContentType; this.templateOutput = templateOutput; + this.purchaseContextType = purchaseContextType; } @@ -272,7 +330,11 @@ public TemplateManager.TemplateOutput getTemplateOutput() { return templateOutput; } - public Map prepareSampleModel(Organization organization, Event event, Optional imageData) { + public PurchaseContextType getPurchaseContextType() { + return purchaseContextType; + } + + public Map prepareSampleModel(Organization organization, PurchaseContext event, Optional imageData) { return Collections.emptyMap(); } @@ -283,9 +345,9 @@ private static Ticket sampleTicket(ZoneId zoneId) { private static Map sampleBillingDocument(Optional imageData, Organization organization, Event event) { Map model = prepareSampleDataForConfirmationEmail(organization, event); imageData.ifPresent(iData -> { - model.put("eventImage", iData.getEventImage()); - model.put("imageWidth", iData.getImageWidth()); - model.put("imageHeight", iData.getImageHeight()); + model.put("eventImage", iData.eventImage()); + model.put("imageWidth", iData.imageWidth()); + model.put("imageHeight", iData.imageHeight()); }); return model; } @@ -297,14 +359,14 @@ private static TicketCategory sampleCategory(ZoneId zoneId) { } private static Ticket sampleTicket(String firstName, String lastName, String email, ZoneId zoneId) { - return new Ticket(0, "597e7e7b-c514-4dcb-be8c-46cf7fe2c36e", ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), 0, "ACQUIRED", 0, - "597e7e7b-c514-4dcb-be8c-46cf7fe2c36e", firstName + " " + lastName, firstName, lastName, email, false, "en", + return new Ticket(0, RESERVATION_ID_VALUE, ZonedDateTime.now(ClockProvider.clock().withZone(zoneId)), 0, "ACQUIRED", 0, + RESERVATION_ID_VALUE, firstName + " " + lastName, firstName, lastName, email, false, "en", 1000, 1000, 80, 0, null, "CHF", List.of(), null, PriceContainer.VatStatus.INCLUDED); } private static TicketReservation sampleTicketReservation(ZoneId zoneId) { var clock = ClockProvider.clock().withZone(zoneId); - return new TicketReservation("597e7e7b-c514-4dcb-be8c-46cf7fe2c36e", new Date(), TicketReservation.TicketReservationStatus.COMPLETE, + return new TicketReservation(RESERVATION_ID_VALUE, new Date(), TicketReservation.TicketReservationStatus.COMPLETE, "Firstname Lastname", "FirstName", "Lastname", "email@email.tld", "billing address", ZonedDateTime.now(clock), ZonedDateTime.now(clock), PaymentProxy.STRIPE, true, null, false, "en", false, null, null, null, "123456", "CH", false, new BigDecimal("8.00"), true, @@ -316,7 +378,7 @@ private static Map prepareSampleDataForConfirmationEmail(Organiz Optional vat = Optional.of("VAT-NR"); List tickets = Collections.singletonList(new TicketWithCategory(sampleTicket(event.getZoneId()), sampleCategory(event.getZoneId()))); OrderSummary orderSummary = new OrderSummary(new TotalPrice(1000, 80, 0, 0, "CHF"), - List.of(new SummaryRow("Ticket", "10.00", "9.20", 1, "9.20", "9.20", 1000, SummaryRow.SummaryType.TICKET, null)), false, "10.00", "0.80", false, false, false, "8", PriceContainer.VatStatus.INCLUDED, "1.00"); + List.of(new SummaryRow("Ticket", "10.00", "9.20", 1, "9.20", "9.20", 1000, SummaryRow.SummaryType.TICKET, null, PriceContainer.VatStatus.INCLUDED)), false, "10.00", "0.80", false, false, false, "8", PriceContainer.VatStatus.INCLUDED, "1.00"); String baseUrl = "http://your-domain.tld"; String reservationUrl = baseUrl + "/reservation-url/"; String reservationShortId = "597e7e7b"; @@ -326,7 +388,7 @@ private static Map prepareSampleDataForConfirmationEmail(Organiz private static Map prepareSampleDataForChargeFailed(Organization organization, Event event) { TicketReservation reservation = sampleTicketReservation(event.getZoneId()); return Map.of( - "reservationId", reservation.getId().substring(0, 8), + RESERVATION_ID, reservation.getId().substring(0, 8), "reservationCancelled", true, "reservation", reservation, "eventName", event.getDisplayName(), @@ -515,7 +577,7 @@ public static Map buildModelForTicketHasBeenCancelledAdmin(Organ model.put("additionalServices", additionalServiceItems.stream() .map(asi -> { Map data = new HashMap<>(); - data.put("name", titleFinder.apply(asi).map(AdditionalServiceText::getValue).orElse("N/A")); + data.put("name", titleFinder.apply(asi).map(AdditionalServiceText::value).orElse("N/A")); data.put("amount", MonetaryUtil.centsToUnit(asi.getFinalPriceCts(), asi.getCurrencyCode()).toString() + event.getCurrency()); data.put("id", asi.getId()); return data; @@ -532,7 +594,7 @@ public static Map buildModelForTicketPDF(Organization organizati Optional imageData, String reservationId, Map additionalFields) { - String qrCodeText = ticketWithMetadata.getTicket().ticketCode(event.getPrivateKey()); + String qrCodeText = ticketWithMetadata.getTicket().ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive()); // Map model = new HashMap<>(); model.put(TICKET_KEY, ticketWithMetadata.getTicket()); @@ -540,7 +602,7 @@ public static Map buildModelForTicketPDF(Organization organizati model.put("ticketCategory", ticketCategory); model.put("event", event); model.put("organization", organization); - model.put("reservationId", reservationId); + model.put(RESERVATION_ID, reservationId); model.put(ADDITIONAL_FIELDS_KEY, additionalFields); model.put(METADATA_ATTRIBUTES_KEY, ticketWithMetadata.getAttributes()); fillTicketValidity(event, ticketCategory, model); @@ -548,15 +610,43 @@ public static Map buildModelForTicketPDF(Organization organizati model.put("qrCodeDataUri", "data:image/png;base64," + Base64.getEncoder().encodeToString(createQRCode(qrCodeText))); imageData.ifPresent(iData -> { - model.put("eventImage", iData.getEventImage()); - model.put("imageWidth", iData.getImageWidth()); - model.put("imageHeight", iData.getImageHeight()); + model.put("eventImage", iData.eventImage()); + model.put("imageWidth", iData.imageWidth()); + model.put("imageHeight", iData.imageHeight()); }); model.put("deskPaymentRequired", Optional.ofNullable(ticketReservation.getPaymentMethod()).orElse(PaymentProxy.STRIPE).isDeskPaymentRequired()); return model; } + public static Map buildModelForSubscriptionPDF(Subscription subscription, + SubscriptionDescriptor subscriptionDescriptor, + Organization organization, + SubscriptionMetadata metadata, + Optional imageData, + String reservationId, + Locale locale, + TicketReservation reservation) { + Map model = new HashMap<>(); + model.put("title", subscriptionDescriptor.getLocalizedTitle(locale)); + model.put("validityTypeNotSet", subscriptionDescriptor.getValidityType() == SubscriptionValidityType.NOT_SET); + model.put("validityTypeStandard", subscriptionDescriptor.getValidityType() == SubscriptionValidityType.STANDARD); + model.put("validityTypeCustom", subscriptionDescriptor.getValidityType() == SubscriptionValidityType.CUSTOM); + model.put("subscription", subscription); + model.put(SUBSCRIPTION_DESCRIPTOR_ATTRIBUTE, subscriptionDescriptor); + model.put("organization", organization); + model.put("reservation", reservation); + model.put(RESERVATION_ID, reservationId); + model.put(METADATA_ATTRIBUTES_KEY, metadata.getProperties()); + model.put("displayPin", metadata.getConfiguration().isDisplayPin()); + imageData.ifPresent(iData -> { + model.put("logo", iData.eventImage); + model.put("imageWidth", iData.imageWidth); + model.put("imageHeight", iData.imageHeight); + }); + return model; + } + // used by WAITING_QUEUE_JOINED public static Map buildModelForWaitingQueueJoined(Organization organization, Event event, CustomerName name) { Map model = new HashMap<>(); @@ -600,21 +690,21 @@ public static ImageData fillWithImageData(FileBlobMetadata m, byte[] image) { return new ImageData(null, null, null); } - @Getter - @AllArgsConstructor - public static class ImageData { - private final String eventImage; - private final Integer imageWidth; - private final Integer imageHeight; + + public record ImageData(String eventImage, Integer imageWidth, Integer imageHeight) { } @Getter - @AllArgsConstructor public static class TicketReservationWithZonedExpiringDate { @Delegate private final TicketReservationInfo reservation; private final Event event; + public TicketReservationWithZonedExpiringDate(TicketReservationInfo reservation, Event event) { + this.reservation = reservation; + this.event = event; + } + public ZonedDateTime getZonedExpiration() { return reservation.getValidity().toInstant().atZone(event.getZoneId()); } diff --git a/src/main/java/alfio/util/Validator.java b/src/main/java/alfio/util/Validator.java index 6adde11401..2b326db6fc 100644 --- a/src/main/java/alfio/util/Validator.java +++ b/src/main/java/alfio/util/Validator.java @@ -28,8 +28,6 @@ import alfio.model.result.ErrorCode; import alfio.model.result.Result; import alfio.model.result.ValidationResult; -import lombok.AllArgsConstructor; -import lombok.RequiredArgsConstructor; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; @@ -40,7 +38,6 @@ import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isAnyBlank; @@ -199,7 +196,7 @@ public static ValidationResult evaluateValidationResult(Errors errors) { if (errors.hasFieldErrors()) { return ValidationResult.failed(errors.getFieldErrors() .stream().map(ValidationResult.ErrorDescriptor::fromFieldError) - .collect(Collectors.toList())); + .toList()); } return ValidationResult.success(); } @@ -217,7 +214,6 @@ public static ValidationResult performAdvancedValidation(AdvancedTicketAssignmen return evaluateValidationResult(errors); } - @AllArgsConstructor public static class TicketFieldsFilterer { private final List additionalFieldsForEvent; @@ -225,6 +221,16 @@ public static class TicketFieldsFilterer { private final Set additionalServiceIds; private final Optional firstTicketInReservation; + public TicketFieldsFilterer(List additionalFieldsForEvent, + Function fromTicketUUIDToTicketCategoryId, + Set additionalServiceIds, + Optional firstTicketInReservation) { + this.additionalFieldsForEvent = additionalFieldsForEvent; + this.fromTicketUUIDToTicketCategoryId = fromTicketUUIDToTicketCategoryId; + this.additionalServiceIds = additionalServiceIds; + this.firstTicketInReservation = firstTicketInReservation; + } + public List getFieldsForTicket(String ticketUUID) { var isFirstTicket = firstTicketInReservation.map(first -> ticketUUID.equals(first.getUuid())).orElse(false); @@ -238,7 +244,7 @@ private static List filterFieldsForTicket(List field.rulesApply(ticketCategoryId)) .filter(f -> f.getContext() == TicketFieldConfiguration.Context.ATTENDEE || (isFirstTicket && Optional.ofNullable(f.getAdditionalServiceId()).filter(additionalServiceIds::contains).isPresent())) - .collect(Collectors.toList()); + .toList(); } } @@ -448,19 +454,27 @@ private static boolean validateDescriptionList(List fieldConf, EventModification.AdditionalField field, Errors errors){ - String duplicateName = fieldConf.stream().filter(f->f.getName().equalsIgnoreCase(field.getName())).map(TicketFieldConfiguration::getName).findAny().orElse(""); + String duplicateName = fieldConf.stream().map(TicketFieldConfiguration::getName) + .filter(name -> name.equalsIgnoreCase(field.getName())) + .findAny() + .orElse(""); if(StringUtils.isNotBlank(duplicateName)){ errors.rejectValue("name", ErrorCode.DUPLICATE); } return evaluateValidationResult(errors); } - @RequiredArgsConstructor + public static class AdvancedTicketAssignmentValidator implements Function> { private final SameCountryValidator vatValidator; private final GroupManager.WhitelistValidator whitelistValidator; + public AdvancedTicketAssignmentValidator(SameCountryValidator vatValidator, GroupManager.WhitelistValidator whitelistValidator) { + this.vatValidator = vatValidator; + this.whitelistValidator = whitelistValidator; + } + @Override public Result apply(AdvancedValidationContext context) { @@ -480,13 +494,25 @@ public Result apply(AdvancedValidationContext context) { } } - @RequiredArgsConstructor + public static class AdvancedValidationContext { private final UpdateTicketOwnerForm updateTicketOwnerForm; private final List ticketFieldConfigurations; private final int categoryId; private final String ticketUuid; private final String prefix; + + public AdvancedValidationContext(UpdateTicketOwnerForm updateTicketOwnerForm, + List ticketFieldConfigurations, + int categoryId, + String ticketUuid, + String prefix) { + this.updateTicketOwnerForm = updateTicketOwnerForm; + this.ticketFieldConfigurations = ticketFieldConfigurations; + this.categoryId = categoryId; + this.ticketUuid = ticketUuid; + this.prefix = prefix; + } } } diff --git a/src/main/java/alfio/util/WorkingDaysAdjusters.java b/src/main/java/alfio/util/WorkingDaysAdjusters.java index 181f5db162..40502968a9 100644 --- a/src/main/java/alfio/util/WorkingDaysAdjusters.java +++ b/src/main/java/alfio/util/WorkingDaysAdjusters.java @@ -16,8 +16,6 @@ */ package alfio.util; -import lombok.experimental.UtilityClass; - import java.time.DayOfWeek; import java.time.LocalTime; import java.time.temporal.ChronoUnit; @@ -25,12 +23,14 @@ import java.time.temporal.TemporalAdjuster; import java.util.*; -@UtilityClass -public class WorkingDaysAdjusters { +public final class WorkingDaysAdjusters { private static final Set MON_FRI = EnumSet.complementOf(EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY)); private static final List ALL_DAY = Collections.singletonList(new HoursRange(LocalTime.of(8, 0, 0), LocalTime.of(20, 0, 0))); + private WorkingDaysAdjusters() { + } + public static TemporalAdjuster defaultWorkingDays() { return temporal -> adjust(temporal, MON_FRI, ALL_DAY); } diff --git a/src/main/java/alfio/util/Wrappers.java b/src/main/java/alfio/util/Wrappers.java index cb2b2bad21..23c1fd1ae7 100644 --- a/src/main/java/alfio/util/Wrappers.java +++ b/src/main/java/alfio/util/Wrappers.java @@ -16,17 +16,20 @@ */ package alfio.util; -import lombok.experimental.UtilityClass; -import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; -@UtilityClass -@Log4j2 -public class Wrappers { +public final class Wrappers { + + private static final Logger log = LoggerFactory.getLogger(Wrappers.class); + + private Wrappers() { + } public static void voidTransactionWrapper(Consumer consumer, I input) { try { diff --git a/src/main/java/alfio/util/checkin/NameNormalizer.java b/src/main/java/alfio/util/checkin/NameNormalizer.java new file mode 100644 index 0000000000..d24fd64781 --- /dev/null +++ b/src/main/java/alfio/util/checkin/NameNormalizer.java @@ -0,0 +1,42 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.util.checkin; + +// heavily inspired by https://stackoverflow.com/a/5470803 +public class NameNormalizer { + + private NameNormalizer() {} + + public static String normalize(String input) { + StringBuilder sb = new StringBuilder(input.length()); + for (int i=0; i < input.length(); i++) { + sb.append(replaceCharIfNotSupported(input.charAt(i))); + } + return sb.toString(); + } + + private static String replaceCharIfNotSupported(char in) { + if (in == 'Σ') { + return "σς"; + } + char lowercase = Character.toLowerCase(in); + if (lowercase == 'ı') { + return "i"; // special case: we render the turkish ı as i since its uppercase is represented as Latin I + } + return Character.toString(lowercase); + } +} diff --git a/src/main/java/alfio/util/checkin/TicketCheckInUtil.java b/src/main/java/alfio/util/checkin/TicketCheckInUtil.java index fc1a720603..cf2791d818 100644 --- a/src/main/java/alfio/util/checkin/TicketCheckInUtil.java +++ b/src/main/java/alfio/util/checkin/TicketCheckInUtil.java @@ -23,23 +23,24 @@ import alfio.model.TicketCategory; import alfio.repository.EventRepository; import alfio.repository.TicketCategoryRepository; -import lombok.experimental.UtilityClass; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import java.util.*; import java.util.function.Supplier; -@UtilityClass -public class TicketCheckInUtil { +public final class TicketCheckInUtil { public static final String CUSTOM_CHECK_IN_URL = "customCheckInUrl"; public static final String ONLINE_CHECK_IN_URL = "onlineCheckInUrl"; public static final String CUSTOM_CHECK_IN_URL_TEXT = "customCheckInUrlText"; public static final String CUSTOM_CHECK_IN_URL_DESCRIPTION = "customCheckInUrlDescription"; + private TicketCheckInUtil() { + } + public static String ticketOnlineCheckInUrl(Event event, Ticket ticket, String baseUrl) { - var ticketCode = DigestUtils.sha256Hex(ticket.ticketCode(event.getPrivateKey())); + var ticketCode = DigestUtils.sha256Hex(ticket.ticketCode(event.getPrivateKey(), event.supportsQRCodeCaseInsensitive())); return StringUtils.removeEnd(baseUrl, "/") + "/event/" + event.getShortName() + "/ticket/" + ticket.getUuid() + "/check-in/"+ticketCode; } @@ -59,7 +60,7 @@ public static Map getOnlineCheckInInfo(ExtensionManager extensio if(customMetadataOptional.isPresent()) { var ticketMetadata = customMetadataOptional.get(); var joinLink = ticketMetadata.getJoinLink(); - result.put(ONLINE_CHECK_IN_URL, joinLink.getLink()); + result.put(ONLINE_CHECK_IN_URL, joinLink.link()); if(joinLink.hasLinkText()) { result.put(CUSTOM_CHECK_IN_URL_TEXT, joinLink.getLocalizedText(ticketLanguage.getLanguage(), event)); } diff --git a/src/main/java/alfio/util/oauth2/AccessTokenRequestDetails.java b/src/main/java/alfio/util/oauth2/AccessTokenRequestDetails.java index 105d5b9577..3fec4b8000 100644 --- a/src/main/java/alfio/util/oauth2/AccessTokenRequestDetails.java +++ b/src/main/java/alfio/util/oauth2/AccessTokenRequestDetails.java @@ -16,12 +16,6 @@ */ package alfio.util.oauth2; -import lombok.Data; -@Data -public class AccessTokenRequestDetails { - private final String clientId; - private final String clientSecret; - private final String tokenUrl; - private final String code; +public record AccessTokenRequestDetails(String clientId, String clientSecret, String tokenUrl, String code) { } diff --git a/src/main/java/alfio/util/oauth2/AccessTokenResponseDetails.java b/src/main/java/alfio/util/oauth2/AccessTokenResponseDetails.java index a7f5bacbe9..dc4a23de9e 100644 --- a/src/main/java/alfio/util/oauth2/AccessTokenResponseDetails.java +++ b/src/main/java/alfio/util/oauth2/AccessTokenResponseDetails.java @@ -16,12 +16,8 @@ */ package alfio.util.oauth2; -import lombok.Data; - -@Data -public class AccessTokenResponseDetails { - private final String accessToken; - private final String refreshToken; - private final String errorMessage; - private final boolean success; +public record AccessTokenResponseDetails(String accessToken, + String refreshToken, + String errorMessage, + boolean success) { } diff --git a/src/main/java/alfio/util/oauth2/AuthorizationRequestDetails.java b/src/main/java/alfio/util/oauth2/AuthorizationRequestDetails.java index b4c81a38e1..6983969487 100644 --- a/src/main/java/alfio/util/oauth2/AuthorizationRequestDetails.java +++ b/src/main/java/alfio/util/oauth2/AuthorizationRequestDetails.java @@ -16,10 +16,5 @@ */ package alfio.util.oauth2; -import lombok.Data; - -@Data -public class AuthorizationRequestDetails { - private final String authorizationUrl; - private final String state; +public record AuthorizationRequestDetails(String authorizationUrl, String state) { } diff --git a/src/main/resources/alfio/certificates/AppleWWDRCA.cer b/src/main/resources/alfio/certificates/AppleWWDRCA.cer deleted file mode 100644 index d2bb1da641..0000000000 Binary files a/src/main/resources/alfio/certificates/AppleWWDRCA.cer and /dev/null differ diff --git a/src/main/resources/alfio/certificates/AppleWWDRCAG4.cer b/src/main/resources/alfio/certificates/AppleWWDRCAG4.cer new file mode 100644 index 0000000000..b9f0bf298d Binary files /dev/null and b/src/main/resources/alfio/certificates/AppleWWDRCAG4.cer differ diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.48__ADD_CURRENCY_CODE_TO_PROMOCODE.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.48__ADD_CURRENCY_CODE_TO_PROMOCODE.sql new file mode 100644 index 0000000000..6b55268b9c --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.48__ADD_CURRENCY_CODE_TO_PROMOCODE.sql @@ -0,0 +1,18 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter table promo_code add column currency_code varchar(3); \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.1__ADD_RESERVATION_METADATA.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.1__ADD_RESERVATION_METADATA.sql new file mode 100644 index 0000000000..1123487a3d --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.1__ADD_RESERVATION_METADATA.sql @@ -0,0 +1,18 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter table tickets_reservation add column metadata jsonb not null default '{}'; \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.2__ADD_SUBSCRIPTION_METADATA.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.2__ADD_SUBSCRIPTION_METADATA.sql new file mode 100644 index 0000000000..20d99d2722 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.2__ADD_SUBSCRIPTION_METADATA.sql @@ -0,0 +1,18 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter table subscription add column metadata jsonb not null default '{}'; \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql new file mode 100644 index 0000000000..7ee84de81d --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.3__ADDITIONAL_VAT_STATUS.sql @@ -0,0 +1,19 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter type VAT_STATUS ADD VALUE 'CUSTOM_NOT_INCLUDED_EXEMPT'; +alter type VAT_STATUS ADD VALUE 'CUSTOM_INCLUDED_EXEMPT'; \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.4__ADMIN_JOB_ALLOW_DUPLICATES.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.4__ADMIN_JOB_ALLOW_DUPLICATES.sql new file mode 100644 index 0000000000..e68be1789d --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.4__ADMIN_JOB_ALLOW_DUPLICATES.sql @@ -0,0 +1,21 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter table admin_job_queue add column allow_duplicates char(1) default 'N'; +alter table admin_job_queue drop constraint "unique_job_schedule"; +alter table admin_job_queue add constraint "unique_job_schedule" unique(job_name, request_ts, allow_duplicates); + diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.5__SPONSOR_SCAN_OPERATOR.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.5__SPONSOR_SCAN_OPERATOR.sql new file mode 100644 index 0000000000..61557d91a2 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.5__SPONSOR_SCAN_OPERATOR.sql @@ -0,0 +1,21 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +alter table sponsor_scan add column operator text not null default '__DEFAULT__'; +alter table sponsor_scan drop constraint "spsc_unique_ticket"; +alter table sponsor_scan add constraint "spsc_unique_ticket" unique(event_id, ticket_id, user_id, operator); + diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.6__FIX_OLD_RESERVATIONS.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.6__FIX_OLD_RESERVATIONS.sql new file mode 100644 index 0000000000..62113794a6 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49.6__FIX_OLD_RESERVATIONS.sql @@ -0,0 +1,20 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +update tickets_reservation set metadata = '{"finalized": true, "hideContactData": false, "readyForConfirmation": true}' + where status in ('COMPLETE', 'OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT') and metadata = '{}'; + diff --git a/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49__ADD_SUBSCRIPTION_STATUS.sql b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49__ADD_SUBSCRIPTION_STATUS.sql new file mode 100644 index 0000000000..3aa41c71b9 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V204_2.0.0.49__ADD_SUBSCRIPTION_STATUS.sql @@ -0,0 +1,20 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +create type SUBSCRIPTION_DESCRIPTOR_STATUS as enum ('ACTIVE', 'NOT_ACTIVE'); +alter table subscription_descriptor add column + status SUBSCRIPTION_DESCRIPTOR_STATUS not null default 'ACTIVE'; \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/V205_2.0.0.49__UPDATE_SPRING_SESSION.sql b/src/main/resources/alfio/db/PGSQL/V205_2.0.0.49__UPDATE_SPRING_SESSION.sql new file mode 100644 index 0000000000..da18f360b3 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V205_2.0.0.49__UPDATE_SPRING_SESSION.sql @@ -0,0 +1,39 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +CREATE TABLE ALFIO_SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, + SESSION_ID CHAR(36) NOT NULL, + CREATION_TIME BIGINT NOT NULL, + LAST_ACCESS_TIME BIGINT NOT NULL, + MAX_INACTIVE_INTERVAL INT NOT NULL, + EXPIRY_TIME BIGINT NOT NULL, + PRINCIPAL_NAME VARCHAR(100), + CONSTRAINT ALFIO_SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) +); + +CREATE UNIQUE INDEX ALFIO_SPRING_SESSION_IX1 ON ALFIO_SPRING_SESSION (SESSION_ID); +CREATE INDEX ALFIO_SPRING_SESSION_IX2 ON ALFIO_SPRING_SESSION (EXPIRY_TIME); +CREATE INDEX ALFIO_SPRING_SESSION_IX3 ON ALFIO_SPRING_SESSION (PRINCIPAL_NAME); + +CREATE TABLE ALFIO_SPRING_SESSION_ATTRIBUTES ( + SESSION_PRIMARY_ID CHAR(36) NOT NULL, + ATTRIBUTE_NAME VARCHAR(200) NOT NULL, + ATTRIBUTE_BYTES BYTEA NOT NULL, + CONSTRAINT ALFIO_SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT ALFIO_SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES ALFIO_SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE +); \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/V205_2.0.0.50__QR_CASE_INSENSITIVE_MARKER.sql b/src/main/resources/alfio/db/PGSQL/V205_2.0.0.50__QR_CASE_INSENSITIVE_MARKER.sql new file mode 100644 index 0000000000..94592f8317 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/V205_2.0.0.50__QR_CASE_INSENSITIVE_MARKER.sql @@ -0,0 +1,18 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +-- this is only meant to be a marker and act as a baseline for applying the new "case insensitive" QR Code generation \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__000_VIEW_drops.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__000_VIEW_drops.sql index 42796789de..77f8f8ef15 100644 --- a/src/main/resources/alfio/db/PGSQL/afterMigrate__000_VIEW_drops.sql +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__000_VIEW_drops.sql @@ -30,4 +30,5 @@ drop view if exists basic_event_with_optional_subscription; drop view if exists reservation_and_subscription_and_tx; drop view if exists extension_capabilities; drop view if exists reservation_with_purchase_context; -drop view if exists available_subscriptions_by_event; \ No newline at end of file +drop view if exists available_subscriptions_by_event; +drop view if exists promocode_usage_details; \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__003_VIEW_ticket_category_statistics.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__003_VIEW_ticket_category_statistics.sql index 33c0484145..73705456f7 100644 --- a/src/main/resources/alfio/db/PGSQL/afterMigrate__003_VIEW_ticket_category_statistics.sql +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__003_VIEW_ticket_category_statistics.sql @@ -33,7 +33,8 @@ from coalesce(sold_tickets_count,0) as sold_tickets_count, coalesce(released_count, 0) as released_count, case(bounded) when false then 0 else max_tickets - coalesce(sold_tickets_count,0 ) - coalesce(checked_in_count, 0) - coalesce(pending_count, 0) end as not_sold_tickets, - coalesce(stuck_count, 0) as stuck_count + coalesce(stuck_count, 0) as stuck_count, + category_configuration from (select max_tickets, bounded, id, event_id, expiration < now() as is_expired, access_restricted from ticket_category where tc_status = 'ACTIVE' ) ticket_cat @@ -60,5 +61,8 @@ left join where tickets_reservation.status = 'STUCK' group by category_id) stuck_count on ticket_cat.id = stuck_count.category_id +left join +(select ticket_category_id_fk, jsonb_agg(json_build_object('id', id, 'key', c_key, 'value', c_value, 'configurationPathLevel', 'TICKET_CATEGORY')) category_configuration + from configuration_ticket_category group by 1) tc_settings on ticket_cat.id = tc_settings.ticket_category_id_fk ) as res); \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__004_VIEW_events_statistics.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__004_VIEW_events_statistics.sql index 122e0d3e61..5b1c933497 100644 --- a/src/main/resources/alfio/db/PGSQL/afterMigrate__004_VIEW_events_statistics.sql +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__004_VIEW_events_statistics.sql @@ -15,15 +15,16 @@ -- along with alf.io. If not, see . -- -create view events_statistics as (select +create view events_statistics as ( +select event.id, (select count(id) from ticket where event_id = event.id and status not in ('INVALIDATED', 'EXPIRED')) as available_seats, - case(contains_unbounded_categories) when true then 0 else (select count(id) from ticket where event_id = event.id and status not in ('INVALIDATED', 'EXPIRED')) - allocated_count end as not_allocated_tickets, - pending_count as pending_tickets, - sold_tickets_count as sold_tickets, - (select released_count + count(id) from ticket where event_id = event.id and status = 'RELEASED' and category_id is null) as released_tickets, - stats.checked_in_count as checked_in_tickets, - case(contains_unbounded_categories) when true then + coalesce( case(contains_unbounded_categories) when true then 0 else (select count(id) from ticket where event_id = event.id and status not in ('INVALIDATED', 'EXPIRED')) - allocated_count end, 0) as not_allocated_tickets, + coalesce (pending_count, 0) as pending_tickets, + coalesce (sold_tickets_count, 0) as sold_tickets, + coalesce ( (select released_count + count(id) from ticket where event_id = event.id and status = 'RELEASED' and category_id is null),0) as released_tickets, + coalesce(stats.checked_in_count, 0) as checked_in_tickets, + coalesce (case(contains_unbounded_categories) when true then (select count(id) from ticket where event_id = event.id and status not in ('INVALIDATED', 'EXPIRED')) - allocated_count - released_count @@ -31,18 +32,18 @@ create view events_statistics as (select - checked_in_count_unbounded - pending_count_unbounded - (select count(*) from ticket where status = 'RELEASED' and category_id is null and event_id = event.id) - else 0 end as dynamic_allocation, - case (contains_unbounded_categories) when true then - allocated_count - sold_tickets_count_bounded - checked_in_count_bounded - pending_count_bounded - else - allocated_count - sold_tickets_count - stats.checked_in_count - pending_count - end as not_sold_tickets, - is_containing_orphan_tickets_count > 0 as is_containing_orphan_tickets, - is_containing_stuck_tickets_count > 0 as is_containing_stuck_tickets_count, - public_and_valid_count > 0 as show_public_statistics - -from -(select + else 0 end, 0) as dynamic_allocation, + coalesce ( + case (contains_unbounded_categories) when true then + allocated_count - sold_tickets_count_bounded - checked_in_count_bounded - pending_count_bounded + else + allocated_count - sold_tickets_count - stats.checked_in_count - pending_count + end, 0) as not_sold_tickets, + coalesce (is_containing_orphan_tickets_count > 0, false) as is_containing_orphan_tickets, + coalesce (is_containing_stuck_tickets_count > 0, false) as is_containing_stuck_tickets_count, + coalesce (public_and_valid_count > 0, false) as show_public_statistics +from ( +select sum(sold_tickets_count) as sold_tickets_count, sum(checked_in_count) as checked_in_count, sum(pending_count) as pending_count, @@ -59,4 +60,5 @@ from sum(case (is_containing_stuck_tickets) when true then 1 else 0 end) is_containing_stuck_tickets_count, sum(case (access_restricted = false and is_expired = false) when true then 1 else 0 end) as public_and_valid_count, event_id from ticket_category_statistics group by event_id) as stats -inner join event on event_id = event.id order by event.start_ts, event.end_ts); \ No newline at end of file +right outer join event on event_id = event.id order by event.start_ts, event.end_ts +); \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__009_VIEW_checkin_ticket_event_and_category_info.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__009_VIEW_checkin_ticket_event_and_category_info.sql index 84f35669c9..7d4511e156 100644 --- a/src/main/resources/alfio/db/PGSQL/afterMigrate__009_VIEW_checkin_ticket_event_and_category_info.sql +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__009_VIEW_checkin_ticket_event_and_category_info.sql @@ -121,16 +121,18 @@ create view checkin_ticket_event_and_category_info as e.metadata e_metadata, e.org_id e_org_id, e.locales e_locales, + e.version e_version, (select jsonb_object_agg(tfc.field_name, case tfc.field_type when 'checkbox' then tfv.field_value::jsonb else jsonb_build_array(tfv.field_value) end) as additional_info from ticket_field_value tfv inner join ticket_field_configuration tfc on tfv.ticket_field_configuration_id_fk = tfc.id - where event_id_fk = e.id) tai_additional_info + where event_id_fk = e.id and tfv.ticket_id_fk = t.id) tai_additional_info, + case when t.status = 'ACQUIRED' or t.status = 'TO_BE_PAID' then 0 else 2 end as t_status_priority from ticket t inner join tickets_reservation tr on t.tickets_reservation_id = tr.id inner join ticket_category tc on t.category_id = tc.id inner join event e on e.id = t.event_id - where t.status in ('ACQUIRED', 'CHECKED_IN') + where t.status in ('ACQUIRED', 'CHECKED_IN', 'TO_BE_PAID') and t.first_name is not null and (t.first_name <> '') IS TRUE and t.last_name is not null diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__012_VIEW_subscription_descriptor_statistics.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__012_VIEW_subscription_descriptor_statistics.sql index 58619a68a4..6fbcf6b0b1 100644 --- a/src/main/resources/alfio/db/PGSQL/afterMigrate__012_VIEW_subscription_descriptor_statistics.sql +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__012_VIEW_subscription_descriptor_statistics.sql @@ -48,5 +48,7 @@ create view subscription_descriptor_statistics as ( (select count(*) from subscription where status between 'ACQUIRED' and 'CHECKED_IN' and subscription_descriptor_fk = sd.id) s_sold_count, (select count(*) from subscription where status = 'PENDING' and subscription_descriptor_fk = sd.id) s_pending_count, (select count(*) from subscription_event where subscription_descriptor_id_fk = sd.id) s_events_count - from subscription_descriptor sd order by on_sale_from, on_sale_to nulls last + from subscription_descriptor sd + where sd.status = 'ACTIVE' + order by on_sale_from, on_sale_to nulls last ) \ No newline at end of file diff --git a/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql b/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql new file mode 100644 index 0000000000..7efa613da2 --- /dev/null +++ b/src/main/resources/alfio/db/PGSQL/afterMigrate__016_VIEW_promocode_usage_details.sql @@ -0,0 +1,57 @@ +-- +-- This file is part of alf.io. +-- +-- alf.io is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- alf.io is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with alf.io. If not, see . +-- + +create view promocode_usage_details as ( +with tickets as ( + select t.tickets_reservation_id, json_agg(jsonb_build_object( + 'id', t.uuid, + 'firstName', t.first_name, + 'lastName', t.last_name, + 'type', tc.name, + 'status', t.status + )) items + from ticket t + join ticket_category tc on t.category_id = tc.id + group by t.tickets_reservation_id +), +reservations as ( + select pc.promo_code, tr.event_id_fk, + jsonb_agg(jsonb_build_object( + 'id', tr.id, + 'invoiceNumber', tr.invoice_number, + 'firstName', tr.first_name, + 'lastName', tr.last_name, + 'email', tr.email_address, + 'paymentType', tr.payment_method, + 'finalPriceCts', tr.final_price_cts, + 'currency', tr.currency_code, + 'confirmationTimestamp', to_char(tr.confirmation_ts at time zone 'UTC', 'YYYY-MM-DD') || 'T' || to_char(tr.confirmation_ts at time zone 'UTC', 'HH24:MI:SS.MSZ'), + 'tickets', t.items + )) as agg + from tickets_reservation tr + join promo_code pc ON tr.promo_code_id_fk = pc.id and + pc.organization_id_fk = tr.organization_id_fk and + (pc.event_id_fk is null or tr.event_id_fk = pc.event_id_fk) + join tickets t on t.tickets_reservation_id = tr.id + where tr.promo_code_id_fk is not null and tr.status in ('OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT', 'COMPLETE', 'CANCELLED') + group by pc.promo_code, tr.event_id_fk +) +select r.promo_code, e.id as event_id, e.short_name event_short_name, e.display_name event_display_name, r.agg reservations +from event e + join reservations r on r.event_id_fk = e.id + order by 1 +); diff --git a/src/main/resources/alfio/i18n/README.md b/src/main/resources/alfio/i18n/README.md index 0ff2f8f5c9..1d17016b65 100644 --- a/src/main/resources/alfio/i18n/README.md +++ b/src/main/resources/alfio/i18n/README.md @@ -2,22 +2,26 @@ ### How it works -We use [POEditor](https://poeditor.com/join/project/ttBYTmPYdr) for translating this project in additional languages (including yours!). +We use POEditor for translating this project in additional languages (including yours!). POEditor is so kind to offer us an unlimited open source subscription. **please be advised that we won't accept Pull Requests for translations.** We consider POEditor as our main channel for this kind of modifications. +Here's how you can become a contributor: + #### 1. Tell us about yourself and explain how you can contribute to the project Get in touch with us using our [message board](https://github.com/alfio-event/alf.io/discussions?discussions_q=category%3Atranslations). Tell us how you want to help us, and the languages you're interested in. +This is **mandatory**, as we won't accept "random" requests on POEditor + #### 2. Request access to the POEditor project In order to start contributing, please sign up using [this link](https://poeditor.com/join/project/ttBYTmPYdr) and request to join a translation team. If you don't see your language among the list, please drop us a message using the dedicated [message board](https://github.com/alfio-event/alf.io/discussions?discussions_q=category%3Atranslations). -You can request access on POEditor to any languages except the following: +You can request access on POEditor **to any languages except the following**: - English (main language) - Italian (the core team's mother tongue) diff --git a/src/main/resources/alfio/i18n/public.properties b/src/main/resources/alfio/i18n/public.properties index e80240443e..9b3cbdfd82 100644 --- a/src/main/resources/alfio/i18n/public.properties +++ b/src/main/resources/alfio/i18n/public.properties @@ -15,6 +15,7 @@ common.edit=Edit common.confirm=Confirm locale=en + event.get-your-ticket-for=Get your tickets for {0} event-days.same-day={0} from {1} to {2} @@ -37,6 +38,7 @@ show-subscription.sold-out.message=We''re sorry but currently we don''t have any show-subscription.header.title=Buy a {0} subscription show-event.tickets.left={0} left show-event.category.quantity=Quantity +show-event.additional.custom-amount=Amount show-event.by=By show-event.tickets=Tickets show-event.additional-services=Additional options @@ -146,6 +148,7 @@ reservation-page-complete.ticket-type=Ticket type\: reservation-page-complete.ticket-not-assigned=not yet assigned reservation-page-complete.ticket-nr=Ticket # reservation-page-complete.order-information=Order information: {0} by {1} +reservation-page-complete.reservation.finalization-in-progress=Reservation is being processed. You''ll receive an email as soon as processing is complete. reservation-page-complete.job-title=Job title reservation-page-complete.company=Company @@ -253,6 +256,7 @@ receipt.payment-for=Payment for: #invoice invoice.vat-invoice={0} Invoice +invoice.proforma=Proforma {0} Invoice invoice.credit-note=Credit Note invoice.credit-note.number=Credit Note Number: invoice.invoice=Invoice @@ -596,4 +600,129 @@ time.extended.pattern=HH:mm online.check-in.waiting-room.button=Try again online.check-in.waiting-room.event-started=The event has started but we could not let you in. online.check-in.waiting-room.event-started.contact-organizers=Please try again by clicking on the button below or contact the organizers. -online.check-in.waiting-room.event-ended=Sorry, this event has ended. \ No newline at end of file +online.check-in.waiting-room.event-ended=Sorry, this event has ended. +qr.code=QR Code +link.new-tab=(Opens in a new tab) + + +## admin related keys + +admin.common.add-new=add new +admin.common.name=Name +admin.common.username=Username +admin.common.save=Save +admin.common.cancel=Cancel +admin.common.delete=Delete +admin.common.description=Description +admin.menu.events=Events +admin.menu.subscriptions=Subscriptions +admin.menu.organization=Organization +admin.menu.security=Security +admin.menu.groups=Groups +admin.menu.settings=Configuration +admin.menu.system=System +admin.menu.system.settings=Configuration +admin.menu.system.organizations=Organizations +admin.menu.system.security=Security +admin.dashboard.my-events=My events +admin.dashboard.export-reservations=Export reservations +admin.dashboard.active=Active +admin.dashboard.past=Past +admin.organization.select=Select organization +admin.organization.list.title=Organizations +admin.organization.new.title=Add a new organization +admin.organization.new.organizer-data=Organizer Data +admin.organization.new.advanced-configuration=Advanced Configuration +admin.organization.new.slug=Slug +admin.organization.new.external-id=External ID (open ID organization ID) +admin.user.list.title=Users +admin.user.list.enabled=Enabled +admin.user.list.disable=Disabled +admin.user.list.username=Username +admin.user.list.role=Role +admin.user.list.member-of=Member of +admin.user.list.reset-password=Reset password +admin.user.new.title=User +admin.user.new.organization=Organization +admin.user.new.role=Role +admin.api-key.list.title=System API Key +admin.api-key.list.text= System API Key can be used from external application to create/modify/delete organizations and to create API Keys +admin.api-key.list.download-api-keys=Download all API Keys for +admin.api-key.list.bulk-creation=Bulk creation +admin.api-key.list.api-key=Api key +admin.api-key.list.description=Description +admin.api-key.list.role=Role +admin.api-key.list.member-of=Member of +admin.api-key.list.qr-code=QR Code +admin.api-key.list.enabled=Enable +admin.api-key.list.disable=Disable +admin.api-key.new.title=User +admin.api-key.new.organization=Organization +admin.api-key.new.role=Role +admin.api-key.new.description=Description + +admin.event-dashboard.total-tickets-confirmed=Total tickets confirmed +admin.event-dashboard.tickets-pending=Tickets pending +admin.event-dashboard.gross-income=Gross income +admin.event-dashboard.logistics-info-and-description=Logistic Info and description +admin.event-dashboard.public-url=Public URL +admin.event-dashboard.organized-by=Organized by +admin.event-dashboard.website-url=Website URL +admin.event-dashboard.t-and-c-url=T&C URL +admin.event-dashboard.privacy-policy-url=Privacy Policy URL +admin.event-dashboard.location=Location +admin.event-dashboard.languages=Languages +admin.event-dashboard.start-date-time=Start Date/Time +admin.event-dashboard.end-date-time=End Date/Time +admin.event-dashboard.time-zone=Time Zone +admin.event-dashboard.seats-and-payment-info=Seats and payment info +admin.event-dashboard.tickets-price=Tickets Price +admin.event-dashboard.free-of-charge=Free of charge +admin.event-dashboard.payment-methods=Payment methods +admin.event-dashboard.max-tickets=Max tickets +admin.event-dashboard.vat=VAT (%) +admin.event-dashboard.final-price=Final Price +admin.event-dashboard.categories=Categories +admin.event-dashboard.categories-legend=Here the categories that have been defined for this event. +admin.event-dashboard.active=Active +admin.event-dashboard.expired=Expired +admin.event-dashboard.alert-warning=No categories matching the selected criteria have been found. +admin.event-dashboard.online=Online +admin.event-dashboard.tickets=Tickets +admin.event-dashboard.tokens=Tokens +admin.event-dashboard.options=Options +admin.event-dashboard.send-invitations=Send invitations +admin.event-dashboard.configure=Configure +admin.event-dashboard.alert-message-limited-group=Access to this category has been limited to Group +admin.event-dashboard.alert-message-category-tickets-unknown-state=This category contains tickets whose reservations are in an unknown state. This could happen when we have troubles after receiving a response from the Payment Gateway. Please +admin.event-dashboard.alert-message-category-tickets-unknown-state-link=fix them +admin.event-dashboard.edit-category=Edit category +admin.event-dashboard.message-orphans=This category contains allocated tickets that cannot be sold anymore. Move them to another category: +admin.event-dashboard.apply=apply +admin.event-dashboard.assign-to-dynamic-categories=Assign to dynamic categories +admin.event-dashboard.message-token-generation=Token generation in progress. Please wait 30s and then reload the page. + +admin.event.menu.details=Details +admin.event.menu.attendees-data-to-collect=Attendees'' data to collect +admin.event.menu.promo-codes=Promo Codes +admin.event.menu.polls=Polls +admin.event.menu.reservations=Reservations +admin.event.menu.email-log=E-mail log +admin.event.menu.status=Status +admin.event.menu.waiting-list=Waiting list +admin.event.menu.back-to-event-detail=back to event detail +admin.event.menu.actions=Actions +admin.event.menu.create-reservation=Create reservation +admin.event.menu.import-attendees=Import attendees +admin.event.menu.edit-configuration=Edit configuration +admin.event.menu.customize-templates=Customize templates +admin.event.menu.compose-message=Compose message +admin.event.menu.hide-from-list=Hide from list +admin.event.menu.check-in=Check in +admin.event.menu.copy-this-event=Copy this event +admin.event.menu.download=Download +admin.event.menu.attendees-data=Attendees'' data + +admin.event.menu.sponsors-scan=Sponsors scan +admin.event.menu.all-billing-documents-pdf=All billing documents (PDF) +admin.event.menu.all-billing-excel=All Billing Documents (Excel) diff --git a/src/main/resources/alfio/i18n/public_it.properties b/src/main/resources/alfio/i18n/public_it.properties index 68ba8e7f9b..2b1afb0bce 100644 --- a/src/main/resources/alfio/i18n/public_it.properties +++ b/src/main/resources/alfio/i18n/public_it.properties @@ -1,4 +1,4 @@ -breadcrumb.step1 = Biglietti +breadcrumb.step1 = Seleziona breadcrumb.step2 = Dati di Contatto breadcrumb.step3 = Pagamento breadcrumb.step3.free = Sommario @@ -187,6 +187,7 @@ invoice.payment-instruction = Indicazioni per il pagamento invoice.payment-instruction-no-later-than = Per confermare la tua prenotazione, dobbiamo ricevere il pagamento entro il {0}. invoice.payment-reason = Specificando {0} quale causale del pagamento. invoice.payment-to = Pagamento a\: +invoice.proforma = Fattura Proforma invoice.refund = Questa fattura è stata aggiornata dopo la cancellazione di uno o più biglietti ed il rimborso di {0}. invoice.refund.line-item = Rimborso invoice.regards = Cordiali saluti, @@ -202,6 +203,8 @@ invoice.vat-invoice = Fattura # please do not translate. This is strictly related to the Italian market invoice.vat-not-added = {0} non inclusa come da direttiva sulla Scissione dei Pagamenti invoice.vat-voided = {0} omessa, come da direttive UE +# Fuzzy +link.new-tab = (si apre in un nuovo tab) locale = it my-orders.confirmation-date = Data di conferma my-orders.description = Qui puoi trovare la lista delle tue prenotazioni @@ -286,6 +289,7 @@ reservation-page-complete.phone-number = Numero di telefono reservation-page-complete.please-check-input-fields = Controlla i valori immessi. reservation-page-complete.release-button.text = Rinuncia reservation-page-complete.resend-reservation-email = Invia email prenotazione +reservation-page-complete.reservation.finalization-in-progress = La prenotazione è in fase di conferma. Riceverai una mail non appena il processo è completo. reservation-page-complete.send-ticket-by-email-to = Invia reservation-page-complete.show-ticket = Visualizza reservation-page-complete.subscription = Dettagli Abbonamento @@ -443,6 +447,7 @@ server-error = Si è verificato un errore inatteso. Per favore segnala quanto ac session-expired.header.title = Sessione scaduta show-event.add-to-calendar = Aggiungi al calendario show-event.additional-services = Opzioni aggiuntive +show-event.additional.custom-amount = Importo # show-event.ms show-event.by = Organizzato da show-event.category.quantity = Quantità diff --git a/src/main/resources/alfio/mjml/confirmation-email-for-organizer-html.mjml b/src/main/resources/alfio/mjml/confirmation-email-for-organizer-html.mjml index 9ee0e23876..ab8161da61 100644 --- a/src/main/resources/alfio/mjml/confirmation-email-for-organizer-html.mjml +++ b/src/main/resources/alfio/mjml/confirmation-email-for-organizer-html.mjml @@ -109,5 +109,19 @@ + {{#hasMailFooter}} + + + + + + +
    {{mailFooter}}
    +
    +
    +
    + {{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/mjml/confirmation-email-html.mjml b/src/main/resources/alfio/mjml/confirmation-email-html.mjml index 8a39dd9897..7282278c4b 100644 --- a/src/main/resources/alfio/mjml/confirmation-email-html.mjml +++ b/src/main/resources/alfio/mjml/confirmation-email-html.mjml @@ -61,12 +61,13 @@ - {{#i18n}}email.hello [{{ticketReservation.fullName}}]{{/i18n}}
    {{custom-header-text}} + {{#i18n}}email.hello [{{ticketReservation.fullName}}]{{/i18n}}
    {{^orderSummary.waitingForPayment}}{{#i18n}}email-confirmation.completed [{{event.displayName}}] [{{reservationUrl}}]{{/i18n}}{{/orderSummary.waitingForPayment}} {{#orderSummary.waitingForPayment}}{{#i18n}}email-confirmation.waiting-for-payment [{{event.displayName}}] [{{reservationUrl}}]{{/i18n}}{{/orderSummary.waitingForPayment}} + {{#render-markdown}}{{custom-header-text}}.html{{/render-markdown}} {{#i18n}}email-confirmation.view-reservation{{/i18n}} @@ -87,17 +88,26 @@ {{#orderSummary.summary}} + - {{#i18n}}email-confirmation.summary.category{{/i18n}} + + {{^discount}}{{#i18n}}email-confirmation.summary.category{{/i18n}}{{/discount}} + {{#discount}}{{#i18n}}show-event.promo-code-applied [{{discountCodeDescription}}]{{/i18n}}{{/discount}} + {{name}} + {{^discount}} {{#i18n}}email-confirmation.summary.quantity{{/i18n}} {{amount}} + {{/discount}} {{^orderSummary.free}} - {{#i18n}}email-confirmation.summary.subtotal{{/i18n}} + + {{^discount}}{{#i18n}}email-confirmation.summary.subtotal{{/i18n}}{{/discount}} + {{#discount}}{{#i18n}}reservation.dynamic.discount.description{{/i18n}}{{/discount}} + {{subTotal}} {{event.currency}} {{/orderSummary.free}} @@ -105,6 +115,10 @@ {{^orderSummary.free}}{{^ticketReservation.vatIncluded}} + {{#i18n}}email-confirmation.summary.subtotal{{/i18n}} + {{orderSummary.priceBeforeTaxes}} {{event.currency}} + + {{#i18n}}reservation-page.vat [{{ticketReservation.usedVatPercent}}] [{{vatTranslation}}]{{/i18n}} {{orderSummary.totalVAT}} {{event.currency}} @@ -187,9 +201,12 @@ {{^event.sameDay}} - + {{#i18n}}event-days.not-same-day [{{#format-date}}{{event.begin}} EEEE dd MMMM yyyy locale:{{#i18n}}locale{{/i18n}}{{/format-date}}] [{{#format-date}}{{event.begin}} HH:mm{{/format-date}}]{{/i18n}} + + {{#i18n}}subscription.detail.validity.CUSTOM.to{{/i18n}} + {{#i18n}}event-days.not-same-day [{{#format-date}}{{event.end}} EEEE dd MMMM yyyy locale:{{#i18n}}locale{{/i18n}}{{/format-date}}] [{{#format-date}}{{event.end}} HH:mm (z){{/format-date}}]{{/i18n}} @@ -207,5 +224,19 @@
    {{/custom-footer-text?}} + {{#hasMailFooter}} + + + + + + +
    {{#render-markdown}}{{mailFooter}}.html{{/render-markdown}}
    +
    +
    +
    + {{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/mjml/confirmation-email-subscription-html.mjml b/src/main/resources/alfio/mjml/confirmation-email-subscription-html.mjml index 8991d384ad..66ecc159b8 100644 --- a/src/main/resources/alfio/mjml/confirmation-email-subscription-html.mjml +++ b/src/main/resources/alfio/mjml/confirmation-email-subscription-html.mjml @@ -137,5 +137,19 @@ {{/custom-footer-text?}} + {{#hasMailFooter}} + + + + + + +
    {{mailFooter}}
    +
    +
    +
    + {{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/mjml/custom-message-html.mjml b/src/main/resources/alfio/mjml/custom-message-html.mjml new file mode 100644 index 0000000000..6a483f4a55 --- /dev/null +++ b/src/main/resources/alfio/mjml/custom-message-html.mjml @@ -0,0 +1,110 @@ + + + + + + + + body { + background: white; + color: #393939; + } + .content-section { + background: white; + } + a { + color: #0056b3; + text-decoration: none; + } + a:hover { + color: #0056b3; + text-decoration: underline; + } + + @media (prefers-color-scheme: dark) { + body { + background: black; + color: #ccc; + } + a { + color: inherit; + text-decoration: none; + } + a:hover { + color: inherit; + text-decoration: underline; + } + } + + tr { + line-height:2; + text-align:center; + } + + tr .bottom-border { + border-bottom:2px solid #ecedee; + } + + li { + margin-top: 10px; + } + img.wallet { + padding-top: 20px; + } + + + + + + + + + + + + + + + + + {{event.displayName}} + + + + + + + + + {{#render-markdown}}{{message}}.html{{/render-markdown}} + + + + + {{#walletEnabled}} + + {{#googleWalletEnabled}} + + + + {{/googleWalletEnabled}} + {{#appleWalletEnabled}} + + + + {{/appleWalletEnabled}} + + {{/walletEnabled}} + + + + {{#i18n}}alfio.credits{{/i18n}} + + + + + diff --git a/src/main/resources/alfio/mjml/offline-reservation-expiring-email-for-organizer-html.mjml b/src/main/resources/alfio/mjml/offline-reservation-expiring-email-for-organizer-html.mjml index 50f1791481..72b1f735f1 100644 --- a/src/main/resources/alfio/mjml/offline-reservation-expiring-email-for-organizer-html.mjml +++ b/src/main/resources/alfio/mjml/offline-reservation-expiring-email-for-organizer-html.mjml @@ -67,5 +67,19 @@ + {{#hasMailFooter}} + + + + + + +
    {{mailFooter}}
    +
    +
    +
    + {{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/mjml/ticket-email-html.mjml b/src/main/resources/alfio/mjml/ticket-email-html.mjml index 83ba0a4d4a..05e9731990 100644 --- a/src/main/resources/alfio/mjml/ticket-email-html.mjml +++ b/src/main/resources/alfio/mjml/ticket-email-html.mjml @@ -44,6 +44,9 @@ tr .bottom-border { border-bottom:2px solid #ecedee; } + img.wallet { + padding-top: 20px; + } @@ -123,8 +126,23 @@ - - + + {{#walletEnabled}} + + {{#googleWalletEnabled}} + + + + {{/googleWalletEnabled}} + {{#appleWalletEnabled}} + + + + {{/appleWalletEnabled}} + + {{/walletEnabled}} + + {{#i18n}}email-ticket.view-modify{{/i18n}} @@ -146,6 +164,21 @@ + {{#hasMailFooter}} + + + + + + +
    {{mailFooter}}
    +
    +
    +
    + {{/hasMailFooter}} +
    diff --git a/src/main/resources/alfio/mjml/ticket-email-online-html.mjml b/src/main/resources/alfio/mjml/ticket-email-online-html.mjml index e72cc01a9b..b532fa74bf 100644 --- a/src/main/resources/alfio/mjml/ticket-email-online-html.mjml +++ b/src/main/resources/alfio/mjml/ticket-email-online-html.mjml @@ -161,5 +161,20 @@ {{/custom-footer-text}} + + {{#hasMailFooter}} + + + + + + +
    {{mailFooter}}
    +
    +
    +
    + {{/hasMailFooter}} diff --git a/src/main/resources/alfio/templates/charge-failed-txt.ms b/src/main/resources/alfio/templates/charge-failed-txt.ms index 0e766b5d37..dcd104c396 100644 --- a/src/main/resources/alfio/templates/charge-failed-txt.ms +++ b/src/main/resources/alfio/templates/charge-failed-txt.ms @@ -9,4 +9,5 @@ {{#i18n}}email.kind-regards{{/i18n}} -{{organization.name}} <{{organization.email}}> \ No newline at end of file +{{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/confirmation-email-subscription-txt.ms b/src/main/resources/alfio/templates/confirmation-email-subscription-txt.ms index 09101cfb15..b8a5b62235 100644 --- a/src/main/resources/alfio/templates/confirmation-email-subscription-txt.ms +++ b/src/main/resources/alfio/templates/confirmation-email-subscription-txt.ms @@ -40,4 +40,5 @@ {{custom-footer-text}} {{#i18n}}email.kind-regards{{/i18n}} -{{organization.name}} <{{organization.email}}> \ No newline at end of file +{{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/confirmation-email-txt.ms b/src/main/resources/alfio/templates/confirmation-email-txt.ms index b5ca892dcf..db608ea695 100644 --- a/src/main/resources/alfio/templates/confirmation-email-txt.ms +++ b/src/main/resources/alfio/templates/confirmation-email-txt.ms @@ -1,8 +1,10 @@ {{#i18n}}email.hello [{{ticketReservation.fullName}}]{{/i18n}} -{{custom-header-text}} + {{^orderSummary.waitingForPayment}}{{#i18n}}email-confirmation.completed [{{event.displayName}}] [{{reservationUrl}}]{{/i18n}}{{/orderSummary.waitingForPayment}} {{#orderSummary.waitingForPayment}}{{#i18n}}email-confirmation.waiting-for-payment [{{event.displayName}}] [{{reservationUrl}}]{{/i18n}}{{/orderSummary.waitingForPayment}} +{{custom-header-text}} + #### {{#i18n}}email-confirmation.reservation-summary{{/i18n}} #### {{#orderSummary.summary}} @@ -42,4 +44,5 @@ reservation.confirmation.email.subscription.button: {{subscriptionUrl}} {{custom-footer-text}} {{#i18n}}email.kind-regards{{/i18n}} -{{organization.name}} <{{organization.email}}> \ No newline at end of file +{{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/credit-note-issued-email-txt.ms b/src/main/resources/alfio/templates/credit-note-issued-email-txt.ms index 4cbbed4160..bb62e23e8d 100644 --- a/src/main/resources/alfio/templates/credit-note-issued-email-txt.ms +++ b/src/main/resources/alfio/templates/credit-note-issued-email-txt.ms @@ -4,4 +4,5 @@ {{#i18n}}email.kind-regards{{/i18n}} -{{organization.name}} <{{organization.email}}> \ No newline at end of file +{{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/credit-note.ms b/src/main/resources/alfio/templates/credit-note.ms index 16d4827423..63d80ebc7c 100644 --- a/src/main/resources/alfio/templates/credit-note.ms +++ b/src/main/resources/alfio/templates/credit-note.ms @@ -1,6 +1,10 @@ - + + {{#i18n}}invoice.credit-note{{/i18n}} + + + + + + + + {{#logo}} + + {{/logo}} + + +

    {{title}}

    + +

    {{#i18n}}reservation-page-complete.subscription{{/i18n}}

    + + + + + +
    {{#i18n}}reservation-page-complete.subscription.owner{{/i18n}}:{{subscription.firstName}} {{subscription.lastName}} <{{subscription.email}}>
    +

    {{#subscriptionDescription}}{{/subscriptionDescription}}

    + + {{#displayPin}} +

    {{#i18n}}reservation-page-complete.subscription.pin-description{{/i18n}}

    +

    {{subscription.pin}}

    + +

    {{#i18n}}reservation-page-complete.subscription.id-description{{/i18n}}

    +

    {{subscription.id}}

    +

    + {{/displayPin}} + + + + + + +
    {{#i18n}}ticket.order-information{{/i18n}}{{#i18n}}ticket.order-information-values [{{reservationId}}] [{{reservation.fullName}}]{{/i18n}}
    + + \ No newline at end of file diff --git a/src/main/resources/alfio/templates/ticket-email-online-txt.ms b/src/main/resources/alfio/templates/ticket-email-online-txt.ms index 6bb2f468b0..6168c8a7c4 100644 --- a/src/main/resources/alfio/templates/ticket-email-online-txt.ms +++ b/src/main/resources/alfio/templates/ticket-email-online-txt.ms @@ -27,5 +27,6 @@ {{#i18n}}email.kind-regards{{/i18n}} {{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} {{#i18n}}alfio.credits{{/i18n}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/ticket-email-txt.ms b/src/main/resources/alfio/templates/ticket-email-txt.ms index 5633c0f825..e030591076 100644 --- a/src/main/resources/alfio/templates/ticket-email-txt.ms +++ b/src/main/resources/alfio/templates/ticket-email-txt.ms @@ -20,5 +20,6 @@ {{#i18n}}email.kind-regards{{/i18n}} {{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} {{#i18n}}alfio.credits{{/i18n}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/ticket-has-been-cancelled-txt.ms b/src/main/resources/alfio/templates/ticket-has-been-cancelled-txt.ms index fb5805c2d1..03a7062f43 100644 --- a/src/main/resources/alfio/templates/ticket-has-been-cancelled-txt.ms +++ b/src/main/resources/alfio/templates/ticket-has-been-cancelled-txt.ms @@ -5,4 +5,5 @@ {{#i18n}}email.kind-regards{{/i18n}} -{{organization.name}} <{{organization.email}}> \ No newline at end of file +{{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/ticket-has-changed-owner-txt.ms b/src/main/resources/alfio/templates/ticket-has-changed-owner-txt.ms index efb63ce2fe..e291f021ed 100644 --- a/src/main/resources/alfio/templates/ticket-has-changed-owner-txt.ms +++ b/src/main/resources/alfio/templates/ticket-has-changed-owner-txt.ms @@ -5,4 +5,5 @@ {{#i18n}}email.kind-regards{{/i18n}} -{{organization.name}} <{{organization.email}}> \ No newline at end of file +{{organization.name}} <{{organization.email}}> +{{#hasMailFooter}}{{#render-markdown}}{{mailFooter}}.text{{/render-markdown}}{{/hasMailFooter}} \ No newline at end of file diff --git a/src/main/resources/alfio/templates/ticket.ms b/src/main/resources/alfio/templates/ticket.ms index aa590b4707..ddec71f930 100644 --- a/src/main/resources/alfio/templates/ticket.ms +++ b/src/main/resources/alfio/templates/ticket.ms @@ -1,5 +1,9 @@ - + + {{#i18n}}ticket.ticket{{/i18n}} + + +