diff --git a/.gitignore b/.gitignore index ab6b7b48..5a0eff78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,16 @@ *.idea/* -*/build/* +build/ .gradle/* */.gradle/* local.properties *.iml *.gpg -*.DS_STORE \ No newline at end of file +*.DS_STORE + +# IntelliJ Code Styles +!/.idea/codeStyles/ + +# moko-resources-generated +moko-resources-generated.js +# generated +pack-test-resources-generated.js \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..1bec35e5 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index 8b39c06b..67bf7c7c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Kamel -[![Version](https://img.shields.io/maven-central/v/com.alialbaali.kamel/kamel-core?label=version&color=blue)](https://search.maven.org/search?q=com.alialbaali.kamel) -[![Snapshot](https://img.shields.io/nexus/s/com.alialbaali.kamel/kamel-core?label=snapshot&server=https%3A%2F%2Foss.sonatype.org)](https://oss.sonatype.org/content/repositories/snapshots/com/alialbaali/kamel/) +[![Version](https://img.shields.io/maven-central/v/media.kamel/kamel-core?label=version&color=blue)](https://search.maven.org/search?q=media.kamel) +[![Snapshot](https://img.shields.io/nexus/s/media.kamel/kamel-core?label=snapshot&server=https%3A%2F%2Fs01.oss.sonatype.org)](https://s01.oss.sonatype.org/content/repositories/snapshots/media/kamel/) [![License](https://img.shields.io/github/license/alialbaali/kamel)](http://www.apache.org/licenses/LICENSE-2.0) -[![Kotlin](https://img.shields.io/badge/kotlin-v1.7.0-blue.svg?logo=kotlin)](http://kotlinlang.org) -[![Compose](https://img.shields.io/badge/compose-v1.2.0-alpha2?logo=compose&color=blue)](http://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-v1.8.20-blue.svg?logo=kotlin)](http://kotlinlang.org) +[![Compose Multiplatform](https://img.shields.io/badge/Compose%20Multiplatform-v1.4.0-blue)](https://github.com/JetBrains/compose-multiplatform) -Kamel is an asynchronous media loading library for Compose. It provides a simple, customizable and +Kamel is an asynchronous media loading library for [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform). It provides a simple, customizable and efficient way to load, cache, decode and display images in your application. By default, it uses Ktor client for loading resources. @@ -49,7 +49,7 @@ kotlin { sourceSets { commonMain { dependencies { - implementation("com.alialbaali.kamel:kamel-image:0.4.0") + implementation("media.kamel:kamel-image:0.5.0") // ... } } @@ -63,7 +63,7 @@ Add the dependency to the dependencies block: ```kotlin dependencies { - implementation("com.alialbaali.kamel:kamel-image:0.4.0") + implementation("media.kamel:kamel-image:0.5.0") // ... } ``` @@ -90,9 +90,12 @@ lazyPainterResource(data = Url("https://www.example.com/image.jpg")) // URI lazyPainterResource(data = URI("https://www.example.com/image.png")) -// File +// File (JVM, Native) lazyPainterResource(data = File("/path/to/image.png")) +// File (JS) +lazyPainterResource(data = File(org.w3c.files.File(arrayOf(blob), "/path/to/image.png"))) + // URL lazyPainterResource(data = URL("https://www.example.com/image.jpg")) diff --git a/build.gradle.kts b/build.gradle.kts index 24ded7a6..2c707198 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,9 +9,8 @@ buildscript { repositories { google() mavenCentral() + gradlePluginPortal() maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") - maven(url = "https://dl.bintray.com/kotlin/dokka") - maven(url = "https://kotlin.bintray.com/ktor") } dependencies { @@ -57,8 +56,6 @@ allprojects { google() mavenCentral() maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") - maven(url = "https://dl.bintray.com/kotlin/dokka") - maven(url = "https://kotlin.bintray.com/ktor") } val emptyJavadocJar by tasks.registering(Jar::class) { @@ -107,14 +104,14 @@ allprojects { name = "MavenCentral" - val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + val releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" + val snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = if (version.toString().endsWith("SNAPSHOT")) uri(snapshotsRepoUrl) else uri(releasesRepoUrl) credentials { - username = rootProject.ext["ossrh.username"] as String - password = rootProject.ext["ossrh.password"] as String + username = rootProject.ext["ossrh.username"] as String? ?: "" + password = rootProject.ext["ossrh.password"] as String? ?: "" } } @@ -126,7 +123,8 @@ allprojects { tasks.withType { kotlinOptions { - freeCompilerArgs = listOf("-Xallow-result-return-type", "-Xopt-in=kotlin.RequiresOptIn") + freeCompilerArgs = listOf("-Xallow-result-return-type") + jvmTarget = "11" } } @@ -134,7 +132,7 @@ allprojects { nexusStaging { packageGroup = Kamel.Group - stagingProfileId = rootProject.ext["stagingProfileId"] as String - username = rootProject.ext["ossrh.username"] as String - password = rootProject.ext["ossrh.password"] as String + stagingProfileId = rootProject.ext["stagingProfileId"] as String? ?: "" + username = rootProject.ext["ossrh.username"] as String? ?: "" + password = rootProject.ext["ossrh.password"] as String? ?: "" } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 445e21f7..f1552441 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,5 +1,5 @@ repositories { - jcenter() + mavenCentral() } plugins { diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 357f8428..afaa0a78 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -5,41 +5,59 @@ object Dependencies { const val KotlinReflect = "org.jetbrains.kotlin:kotlin-reflect:${Versions.Kotlin}" object Android { - const val Appcompat = "androidx.appcompat:appcompat:${Versions.Android.Appcompat}" - const val Core = "androidx.core:core-ktx:${Versions.Android.Core}" const val ActivityCompose = "androidx.activity:activity-compose:${Versions.Android.ActivityCompose}" + const val Appcompat = "androidx.appcompat:appcompat:${Versions.Android.Appcompat}" const val GradlePlugin = "com.android.tools.build:gradle:${Versions.AGP}" const val Material = "com.google.android.material:material:${Versions.Android.Material}" + const val Annotation = "androidx.annotation:annotation:${Versions.Android.Annotation}" } object Ktor { const val Core = "io.ktor:ktor-client-core:${Versions.Ktor}" - const val Logging = "io.ktor:ktor-client-logging:${Versions.Ktor}" const val Android = "io.ktor:ktor-client-android:${Versions.Ktor}" + const val Darwin = "io.ktor:ktor-client-darwin:${Versions.Ktor}" + const val Js = "io.ktor:ktor-client-js:${Versions.Ktor}" const val CIO = "io.ktor:ktor-client-cio:${Versions.Ktor}" } + object Coroutines { + const val Core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.Coroutines}" + const val Test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.Coroutines}" + } + object Testing { const val Ktor = "io.ktor:ktor-client-mock:${Versions.Ktor}" - const val Coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.Coroutines}" const val Compose = "org.jetbrains.compose.ui:ui-test-junit4:${Versions.Compose}" + const val MokoResources = "dev.icerock.moko:resources:${Versions.MokoResources}" + } + + object MokoResources { + const val Core = "dev.icerock.moko:resources:${Versions.MokoResources}" + const val Test = "dev.icerock.moko:resources-test:${Versions.MokoResources}" + } + + object XmlUtil { + const val Serialization = "io.github.pdvrieze.xmlutil:serialization:${Versions.XmlUtil}" } } -private object Versions { +object Versions { + + const val Kotlin = "1.8.20" + const val Ktor = "2.3.0" + const val Coroutines = "1.6.4" + const val Compose = "1.4.0" + const val AGP = "7.4.2" + const val MokoResources = "0.22.0" + const val XmlUtil = "0.86.0" - const val Kotlin = "1.7.0" - const val Ktor = "2.0.3" - const val Coroutines = "1.6.3" - const val Compose = "1.2.0-alpha01-dev753" - const val AGP = "7.2.1" object Android { - const val Appcompat = "1.4.2" - const val Core = "1.8.0" - const val ActivityCompose = "1.5.0" - const val Material = "1.6.1" + const val ActivityCompose = "1.7.1" + const val Appcompat = "1.6.1" + const val Material = "1.8.0" + const val Annotation = "1.6.0" } } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Kamel.kt b/buildSrc/src/main/kotlin/Kamel.kt index 3b3693d1..5ddd45ea 100644 --- a/buildSrc/src/main/kotlin/Kamel.kt +++ b/buildSrc/src/main/kotlin/Kamel.kt @@ -1,4 +1,4 @@ object Kamel { - const val Group = "com.alialbaali.kamel" - const val Version = "0.4.1" + const val Group = "media.kamel" + const val Version = "0.5.0-SNAPSHOT" } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Plugins.kt b/buildSrc/src/main/kotlin/Plugins.kt index 5e9b8fdb..b95322ea 100644 --- a/buildSrc/src/main/kotlin/Plugins.kt +++ b/buildSrc/src/main/kotlin/Plugins.kt @@ -9,11 +9,11 @@ inline val PluginDependenciesSpec.compose: PluginDependencySpec inline val PluginDependenciesSpec.multiplatform: PluginDependencySpec get() = kotlin("multiplatform") -inline val PluginDependenciesSpec.`nexus-staging`: PluginDependencySpec - get() = id("io.codearte.nexus-staging") version "0.22.0" +inline val PluginDependenciesSpec.mokoResources: PluginDependencySpec + get() = id("dev.icerock.mobile.multiplatform-resources") version Versions.MokoResources -inline val PluginDependenciesSpec.dokka: PluginDependencySpec - get() = id("org.jetbrains.dokka") version "1.4.20" +inline val PluginDependenciesSpec.`nexus-staging`: PluginDependencySpec + get() = id("io.codearte.nexus-staging") version "0.30.0" inline val PluginDependenciesSpec.`android-library`: PluginDependencySpec get() = id("com.android.library") diff --git a/buildSrc/src/main/kotlin/Targets.kt b/buildSrc/src/main/kotlin/Targets.kt new file mode 100644 index 00000000..bb0a4a7c --- /dev/null +++ b/buildSrc/src/main/kotlin/Targets.kt @@ -0,0 +1,14 @@ +object Targets { + + val iosTargets = arrayOf( + "iosArm64", "iosX64", "iosSimulatorArm64", + ) + val macosTargets = arrayOf( + "macosX64", "macosArm64", + ) + val darwinTargets = iosTargets + macosTargets + val linuxTargets = arrayOf() + val mingwTargets = arrayOf() + val nativeTargets = linuxTargets + darwinTargets + mingwTargets + +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index b8822f8b..cefec6eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,15 @@ +org.gradle.jvmargs=-Xmx3g kotlin.code.style=official +kotlin.native.cacheKind=none +kotlin.native.useEmbeddableCompilerJar=true +kotlin.mpp.enableCInteropCommonization=true +kotlin.mpp.androidSourceSetLayoutVersion=2 +compose.desktop.verbose=true + android.useAndroidX=true -kotlin.mpp.stability.nowarn=true \ No newline at end of file +android.disableAutomaticComponentCreation=true +kotlin.mpp.stability.nowarn=true + +org.jetbrains.compose.experimental.jscanvas.enabled=true +org.jetbrains.compose.experimental.macos.enabled=true +org.jetbrains.compose.experimental.uikit.enabled=true \ No newline at end of file diff --git a/gradle/pack-core-tests-resources.gradle.kts b/gradle/pack-core-tests-resources.gradle.kts new file mode 100644 index 00000000..e3ab88bf --- /dev/null +++ b/gradle/pack-core-tests-resources.gradle.kts @@ -0,0 +1,36 @@ +/*** + * How to handle Web Workers "standard" syntax with webpack: + * https://stackoverflow.com/a/41630622/1363742 + */ +fun createWebpackConfig(){ + val rootProjectAbsPath = rootProject.projectDir.absolutePath + val path = """"$rootProjectAbsPath/kamel-core/build/generated/moko/jsMain/iokamelcore/res"""" + val webpackConfig = File(projectDir, "webpack.config.d/pack-test-resources-generated.js") + val configText = + """const path = require('path'); + +const mokoResourcePath = path.resolve($path); + +config.module.rules.push( + { + test: /\.(.*)/, + include: [ + path.resolve(mokoResourcePath) + ], + type: 'asset/resource' + } +); + +config.resolve.modules.push( + path.resolve(mokoResourcePath) +);""" + webpackConfig.writeText(configText) +} + +tasks.create("createPackResourcesWebpackConfig") { + doFirst { + createWebpackConfig() + } +} + +tasks.getByName("jsJar").dependsOn("createPackResourcesWebpackConfig") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c0..249e5832 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 1565a526..fae08049 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sun Jul 10 06:06:14 TRT 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME \ No newline at end of file diff --git a/gradlew b/gradlew index 4f906e0c..a69d9cb6 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,101 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -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 - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9..53a6b238 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/kamel-core/build.gradle.kts b/kamel-core/build.gradle.kts index b461c4d6..c14b4b5f 100644 --- a/kamel-core/build.gradle.kts +++ b/kamel-core/build.gradle.kts @@ -1,5 +1,10 @@ -import org.jetbrains.compose.compose import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode +import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractExecutable +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink +import org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutImpl +import java.io.FileFilter plugins { multiplatform @@ -13,14 +18,48 @@ kotlin { explicitApi = ExplicitApiMode.Warning jvm() + js(IR) { + browser() + } + for (target in Targets.macosTargets) { + targets.add( + (presets.getByName(target).createTarget(target) as KotlinNativeTarget).apply { + binaries.forEach { + it.apply { + freeCompilerArgs += listOf( + "-linker-option", "-framework", "-linker-option", "Metal" + ) + } + } + } + ) + } + for (target in Targets.iosTargets) { + targets.add( + (presets.getByName(target).createTarget(target) as KotlinNativeTarget).apply { + binaries.forEach { + it.apply { + freeCompilerArgs += listOf( + "-linker-option", "-framework", "-linker-option", "Metal", + "-linker-option", "-framework", "-linker-option", "CoreText", + "-linker-option", "-framework", "-linker-option", "CoreGraphics" + ) + } + } + } + ) + } + + sourceSets { val commonMain by getting { dependencies { - api(compose.ui) - api(compose.foundation) - api(compose.runtime) + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.runtime) + implementation(Dependencies.Coroutines.Core) api(Dependencies.Ktor.Core) } } @@ -28,23 +67,48 @@ kotlin { val commonTest by getting { dependencies { implementation(project(":kamel-tests")) - implementation(kotlin("test-common")) - implementation(kotlin("test-annotations-common")) + implementation(kotlin("test")) implementation(Dependencies.Testing.Ktor) - implementation(Dependencies.Testing.Coroutines) - implementation(Dependencies.Testing.Compose) + implementation(Dependencies.Coroutines.Test) } } val jvmMain by getting { + dependsOn(commonMain) dependencies { implementation(Dependencies.KotlinReflect) } } val jvmTest by getting { - dependencies { - implementation(kotlin("test-junit")) + } + + val nonJvmMain by creating { + dependsOn(commonMain) + } + + val nonJvmTest by creating { + dependsOn(commonTest) + } + + val jsMain by getting { + dependsOn(nonJvmMain) + } + + val darwinMain by creating { + dependsOn(nonJvmMain) + } + + val darwinTest by creating { + dependsOn(nonJvmTest) + } + + Targets.darwinTargets.forEach { target -> + getByName("${target}Main") { + dependsOn(darwinMain) + } + getByName("${target}Test") { + dependsOn(darwinTest) } } @@ -54,13 +118,66 @@ kotlin { } } - targets.all { - compilations.all { - kotlinOptions { - freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn") + } +} + +// https://youtrack.jetbrains.com/issue/KT-46466 +val dependsOnTasks = mutableListOf() +tasks.withType().configureEach { + dependsOnTasks.add(this.name.replace("publish", "sign").replaceAfter("Publication", "")) + dependsOn(dependsOnTasks) +} + + +// todo: Remove when resolved: https://github.com/icerockdev/moko-resources/issues/372 +tasks.withType() + .matching { linkTask -> + linkTask.binary is AbstractExecutable + } + .configureEach { + val task: KotlinNativeLink = this + + this.doLast { + val binary: NativeBinary = task.binary + val outputDir: File = task.outputFile.get().parentFile + task.libraries + .filter { library -> library.extension == "klib" } + .filter(File::exists) + .forEach { inputFile -> + val klibKonan = org.jetbrains.kotlin.konan.file.File(inputFile.path) + val klib = KotlinLibraryLayoutImpl( + klib = klibKonan, + component = "default" + ) + val layout = klib.extractingToTemp + + // extracting bundles + layout + .resourcesDir + .absolutePath + .let(::File) + .listFiles(FileFilter { it.extension == "bundle" }) + // copying bundles to app + ?.forEach { bundleFile -> + logger.info("${bundleFile.absolutePath} copying to $outputDir") + bundleFile.copyRecursively( + target = File(outputDir, bundleFile.name), + overwrite = true + ) + } } - } } - } + + +// todo: remove after https://github.com/icerockdev/moko-resources/issues/392 resolved +// copy resources from kamel-tests into the proper directory for kamel-samples so they are packaged for +// the web app +tasks.register("jsCopyResourcesFromKamelTests") { + from("../kamel-tests/build/generated/moko/jsMain/iokameltests/res") + into("build/generated/moko/jsMain/iokamelcore/res") + dependsOn(":kamel-tests:generateMRjsMain") } +tasks.getByName("jsProcessResources").dependsOn("jsCopyResourcesFromKamelTests") + +apply(from = "$rootDir/gradle/pack-core-tests-resources.gradle.kts") \ No newline at end of file diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/ImageLoading.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/ImageLoading.kt index e7a877ee..3ac12bf6 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/ImageLoading.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/ImageLoading.kt @@ -13,6 +13,7 @@ import io.kamel.core.utils.findDecoderFor import io.kamel.core.utils.findFetcherFor import io.kamel.core.utils.mapInput import kotlinx.coroutines.flow.* +import kotlin.reflect.KClass /** * Loads an [ImageBitmap]. This includes mapping, fetching, decoding and caching the image resource. @@ -21,10 +22,11 @@ import kotlinx.coroutines.flow.* * @see Mapper * @see Cache */ -public fun KamelConfig.loadImageBitmapResource( - data: Any, - resourceConfig: ResourceConfig -): Flow> = loadResource(data, resourceConfig, imageBitmapCache) +public fun KamelConfig.loadImageBitmapResource( + data: I, + resourceConfig: ResourceConfig, + dataKClass: KClass<*> = data::class, +): Flow> = loadResource(data, dataKClass, resourceConfig, imageBitmapCache) /** * Loads an [ImageVector]. This includes mapping, fetching, decoding and caching the image resource. @@ -35,8 +37,9 @@ public fun KamelConfig.loadImageBitmapResource( */ public fun KamelConfig.loadImageVectorResource( data: Any, - resourceConfig: ResourceConfig -): Flow> = loadResource(data, resourceConfig, imageVectorCache) + resourceConfig: ResourceConfig, + dataKClass: KClass<*> = data::class +): Flow> = loadResource(data, dataKClass, resourceConfig, imageVectorCache) /** * Loads SVG [Painter]. This includes mapping, fetching, decoding and caching the image resource. @@ -47,15 +50,17 @@ public fun KamelConfig.loadImageVectorResource( */ public fun KamelConfig.loadSvgResource( data: Any, - resourceConfig: ResourceConfig -): Flow> = loadResource(data, resourceConfig, svgCache) + resourceConfig: ResourceConfig, + dataKClass: KClass<*> = data::class +): Flow> = loadResource(data, dataKClass, resourceConfig, svgCache) private inline fun KamelConfig.loadResource( data: Any, + dataKClass: KClass<*>, resourceConfig: ResourceConfig, cache: Cache, ): Flow> = flow { - val output = mapInput(data) + val output = mapInput(data, dataKClass) val cachedData = cache[output] if (cachedData != null) { val resource = Resource.Success(cachedData, DataSource.Memory) diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfig.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfig.kt index 803a229a..fed090ee 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfig.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfig.kt @@ -7,6 +7,7 @@ import io.kamel.core.cache.Cache import io.kamel.core.decoder.Decoder import io.kamel.core.fetcher.Fetcher import io.kamel.core.mapper.Mapper +import kotlin.reflect.KClass public const val DefaultCacheSize: Int = 100 @@ -20,7 +21,7 @@ public interface KamelConfig { public val decoders: List> - public val mappers: List> + public val mappers: Map, Mapper> /** * Number of entries to cache. Default is 100. diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfigBuilder.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfigBuilder.kt index 8ba00f96..fff29124 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfigBuilder.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/config/KamelConfigBuilder.kt @@ -15,10 +15,13 @@ import io.kamel.core.mapper.Mapper import io.kamel.core.mapper.StringMapper import io.kamel.core.mapper.URIMapper import io.kamel.core.mapper.URLMapper +import io.kamel.core.utils.URI +import io.kamel.core.utils.URL import io.ktor.client.* import io.ktor.client.engine.* import io.ktor.client.request.* import io.ktor.http.* +import kotlin.reflect.KClass public class KamelConfigBuilder { @@ -26,7 +29,7 @@ public class KamelConfigBuilder { internal val decoders: MutableList> = mutableListOf() - internal val mappers: MutableList> = mutableListOf() + internal val mappers: MutableMap, Mapper> = mutableMapOf() public var imageBitmapCacheSize: Int = 0 @@ -43,7 +46,7 @@ public class KamelConfigBuilder { } public fun mapper(mapper: Mapper) { - mappers += mapper as Mapper + mappers[mapper.inputKClass] = mapper as Mapper } public fun build(): KamelConfig = object : KamelConfig { @@ -52,7 +55,7 @@ public class KamelConfigBuilder { override val decoders: List> = this@KamelConfigBuilder.decoders - override val mappers: List> = this@KamelConfigBuilder.mappers + override val mappers: Map, Mapper> = this@KamelConfigBuilder.mappers override val imageBitmapCache: Cache = LruCache(imageBitmapCacheSize) @@ -120,7 +123,7 @@ public fun KamelConfigBuilder.takeFrom(config: KamelConfig): KamelConfigBuilder svgCacheSize = config.svgCache.maxSize config.fetchers.forEach { fetcher(it) } config.decoders.forEach { decoder(it) } - config.mappers.forEach { mapper(it) } + config.mappers.values.forEach { mapper(it) } return this } \ No newline at end of file diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/config/ResourceConfigBuilder.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/config/ResourceConfigBuilder.kt index 112e21f7..64d1b986 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/config/ResourceConfigBuilder.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/config/ResourceConfigBuilder.kt @@ -1,11 +1,10 @@ package io.kamel.core.config -import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.unit.Density -import io.kamel.core.utils.IO +import io.kamel.core.utils.Kamel +import io.kamel.core.utils.supervisorJob import io.ktor.client.request.* import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlin.coroutines.CoroutineContext public class ResourceConfigBuilder { @@ -20,7 +19,7 @@ public class ResourceConfigBuilder { * CoroutineContext used while loading the resource. * @see ResourceConfig.coroutineContext */ - public var coroutineContext: CoroutineContext = Job() + Dispatchers.IO + public var coroutineContext: CoroutineContext = supervisorJob.plus(Dispatchers.Kamel) /** * Screen density. diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/decoder/Decoder.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/decoder/Decoder.kt index fece079a..e1f6490f 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/decoder/Decoder.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/decoder/Decoder.kt @@ -2,11 +2,17 @@ package io.kamel.core.decoder import io.kamel.core.config.ResourceConfig import io.ktor.utils.io.* +import kotlin.reflect.KClass /** * Decodes [ByteReadChannel] to [T]. */ -public interface Decoder { +public interface Decoder { + + /** + * The KClass of the output of this decoder + */ + public val outputKClass: KClass /** * Decodes [channel] to [T]. diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/Fetcher.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/Fetcher.kt index 80a71252..bebdb8c4 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/Fetcher.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/Fetcher.kt @@ -5,12 +5,18 @@ import io.kamel.core.Resource import io.kamel.core.config.ResourceConfig import io.ktor.utils.io.* import kotlinx.coroutines.flow.Flow +import kotlin.reflect.KClass /** * Fetches and transfers data into a [ByteReadChannel] asynchronously. */ public interface Fetcher { + /** + * The KClass type for which this fetcher supports as a data input + */ + public val inputDataKClass: KClass + /** * Source from where data has been loaded. */ diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/HttpFetcher.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/HttpFetcher.kt index 7b6076b9..1045b57f 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/HttpFetcher.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/fetcher/HttpFetcher.kt @@ -11,12 +11,15 @@ import io.ktor.http.* import io.ktor.utils.io.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow +import kotlin.reflect.KClass /** * Fetcher that fetches [ByteReadChannel] from network using [Url]. */ internal class HttpFetcher(private val client: HttpClient) : Fetcher { + override val inputDataKClass: KClass = Url::class + override val source: DataSource = DataSource.Network override val Url.isSupported: Boolean diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mapper.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mapper.kt index bdccb32f..c426eff4 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mapper.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mapper.kt @@ -1,12 +1,17 @@ package io.kamel.core.mapper +import kotlin.reflect.KClass + /** * Mapper used to map input [I] to output [O]. * @see StringMapper * @see URLMapper * @see URIMapper */ -public fun interface Mapper { +public interface Mapper { + + public val inputKClass: KClass + public val outputKClass: KClass /** * Maps input [I] to output [O]. diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mappers.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mappers.kt index 4da863c1..2f8d94b8 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mappers.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/mapper/Mappers.kt @@ -3,8 +3,17 @@ package io.kamel.core.mapper import io.kamel.core.utils.URI import io.kamel.core.utils.URL import io.ktor.http.* +import kotlin.reflect.KClass -internal val StringMapper: Mapper = Mapper { Url(it) } +internal val StringMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = String::class + override val outputKClass: KClass + get() = Url::class + + override fun map(input: String): Url = Url(input) + +} internal expect val URLMapper: Mapper diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/ConfigUtils.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/ConfigUtils.kt index 22b5ee70..c358df49 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/ConfigUtils.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/ConfigUtils.kt @@ -3,22 +3,10 @@ package io.kamel.core.utils import io.kamel.core.config.KamelConfig import io.kamel.core.decoder.Decoder import io.kamel.core.fetcher.Fetcher +import kotlin.reflect.KClass -internal fun KamelConfig.mapInput(input: Any): Any { - - var output: Any? = null - - mappers.findLast { - - output = try { - it.map(input) - } catch (e: Throwable) { - null - } - - output != null - } - +internal fun KamelConfig.mapInput(input: Any, inputKClass: KClass<*>): Any { + val output = mappers[inputKClass]?.map(input) return output ?: input } diff --git a/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/Platform.kt b/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/Platform.kt index cc274657..23bc72e3 100644 --- a/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/Platform.kt +++ b/kamel-core/src/commonMain/kotlin/io/kamel/core/utils/Platform.kt @@ -2,8 +2,11 @@ package io.kamel.core.utils import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob -internal expect val Dispatchers.IO: CoroutineDispatcher +internal val supervisorJob = SupervisorJob() + +internal expect val Dispatchers.Kamel: CoroutineDispatcher public expect class File diff --git a/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigBuilderTest.kt b/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigBuilderTest.kt index 095abfb1..a50e4650 100644 --- a/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigBuilderTest.kt +++ b/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigBuilderTest.kt @@ -7,6 +7,8 @@ import io.kamel.core.mapper.Mapper import io.kamel.core.mapper.StringMapper import io.kamel.core.mapper.URIMapper import io.kamel.core.mapper.URLMapper +import io.kamel.core.utils.URI +import io.kamel.core.utils.URL import io.kamel.tests.HttpMockEngine import kotlin.test.BeforeTest import kotlin.test.Test @@ -43,7 +45,8 @@ class KamelConfigBuilderTest { builder.stringMapper() assertTrue { builder.mappers.size == 1 } - assertTrue { builder.mappers.contains>(StringMapper) } + assertTrue { builder.mappers.keys.contains(String::class) } + assertTrue { builder.mappers.values.contains>(StringMapper) } } @Test @@ -51,7 +54,8 @@ class KamelConfigBuilderTest { builder.urlMapper() assertTrue { builder.mappers.size == 1 } - assertTrue { builder.mappers.contains>(URLMapper) } + assertTrue { builder.mappers.keys.contains(URL::class) } + assertTrue { builder.mappers.values.contains>(URLMapper) } } @Test @@ -59,7 +63,8 @@ class KamelConfigBuilderTest { builder.uriMapper() assertTrue { builder.mappers.size == 1 } - assertTrue { builder.mappers.contains>(URIMapper) } + assertTrue { builder.mappers.keys.contains(URI::class) } + assertTrue { builder.mappers.values.contains>(URIMapper) } } @Test @@ -83,8 +88,10 @@ class KamelConfigBuilderTest { builder.takeFrom(configBuilder) assertTrue { builder.fetchers.contains>(FileFetcher) } - assertTrue { builder.mappers.contains>(URIMapper) } - assertTrue { builder.mappers.contains>(StringMapper) } + assertTrue { builder.mappers.keys.contains(URI::class) } + assertTrue { builder.mappers.values.contains>(URIMapper) } + assertTrue { builder.mappers.keys.contains(String::class) } + assertTrue { builder.mappers.values.contains>(StringMapper) } assertEquals(100, builder.build().imageBitmapCache.maxSize) } @@ -99,8 +106,10 @@ class KamelConfigBuilderTest { builder.takeFrom(configBuilder.build()) assertTrue { builder.fetchers.contains>(FileFetcher) } - assertTrue { builder.mappers.contains>(URIMapper) } - assertTrue { builder.mappers.contains>(StringMapper) } + assertTrue { builder.mappers.keys.contains(URI::class) } + assertTrue { builder.mappers.values.contains>(URIMapper) } + assertTrue { builder.mappers.keys.contains(String::class) } + assertTrue { builder.mappers.values.contains>(StringMapper) } assertEquals(100, builder.build().imageBitmapCache.maxSize) } diff --git a/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigUtilsTest.kt b/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigUtilsTest.kt index c089ff50..8efa2bc0 100644 --- a/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigUtilsTest.kt +++ b/kamel-core/src/commonTest/kotlin/io/kamel/core/config/KamelConfigUtilsTest.kt @@ -9,6 +9,7 @@ import io.kamel.tests.HttpMockEngine import io.kamel.tests.TestStringUrl import io.ktor.http.* import io.ktor.utils.io.* +import kotlin.reflect.KClass import kotlin.test.Test import kotlin.test.assertFails import kotlin.test.assertTrue @@ -26,21 +27,21 @@ class KamelConfigUtilsTest { @Test fun testMapStringInput() { - val result = config.mapInput(TestStringUrl) + val result = config.mapInput(TestStringUrl, String::class) assertTrue(result is Url) } @Test fun testMapURLInput() { - val result = config.mapInput(createURL(TestStringUrl)) + val result = config.mapInput(createURL(TestStringUrl), URL::class) assertTrue(result is Url) } @Test fun testMapURIInput() { - val result = config.mapInput(createURI(TestStringUrl)) + val result = config.mapInput(createURI(TestStringUrl), URI::class) assertTrue(result is Url) } @@ -79,6 +80,9 @@ class KamelConfigUtilsTest { fun KamelConfigBuilder.fakeImageBitmapDecoder() = decoder(FakeImageBitmapDecoder) private object FakeImageBitmapDecoder : Decoder { + + override val outputKClass: KClass = ImageBitmap::class + override suspend fun decode(channel: ByteReadChannel, resourceConfig: ResourceConfig): ImageBitmap { return ImageBitmap(1, 1) } diff --git a/kamel-core/src/jvmTest/kotlin/io/kamel/core/fetcher/HttpFetcherTest.kt b/kamel-core/src/commonTest/kotlin/io/kamel/core/fetcher/HttpFetcherTest.kt similarity index 94% rename from kamel-core/src/jvmTest/kotlin/io/kamel/core/fetcher/HttpFetcherTest.kt rename to kamel-core/src/commonTest/kotlin/io/kamel/core/fetcher/HttpFetcherTest.kt index 333f1040..e8a84541 100644 --- a/kamel-core/src/jvmTest/kotlin/io/kamel/core/fetcher/HttpFetcherTest.kt +++ b/kamel-core/src/commonTest/kotlin/io/kamel/core/fetcher/HttpFetcherTest.kt @@ -48,7 +48,7 @@ class HttpFetcherTest { } @Test - fun testFetchingEmptyImageBytes(): Unit = runTest { + fun testFetchingEmptyImageBytes() = runTest { val url = Url("/emptyImage.jpg") val resource = fetcher.fetch(url, resourceConfig) .first { !it.isLoading } @@ -59,7 +59,7 @@ class HttpFetcherTest { } @Test - fun testFetchingNonEmptyImageBytes(): Unit = runTest { + fun testFetchingNonEmptyImageBytes() = runTest { val url = Url("/image.svg") val resource = fetcher.fetch(url, resourceConfig) .first { !it.isLoading } diff --git a/kamel-core/src/darwinMain/kotlin/io/kamel/core/fetcher/FileFetcher.kt b/kamel-core/src/darwinMain/kotlin/io/kamel/core/fetcher/FileFetcher.kt new file mode 100644 index 00000000..67b964a2 --- /dev/null +++ b/kamel-core/src/darwinMain/kotlin/io/kamel/core/fetcher/FileFetcher.kt @@ -0,0 +1,32 @@ +package io.kamel.core.fetcher + +import io.kamel.core.DataSource +import io.kamel.core.Resource +import io.kamel.core.config.ResourceConfig +import io.kamel.core.utils.File +import io.ktor.utils.io.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlin.reflect.KClass + +/** + * Fetcher that fetchers [ByteReadChannel] from a file. + */ +internal actual object FileFetcher : Fetcher { + + override val inputDataKClass: KClass = File::class + + override val source: DataSource = DataSource.Disk + + override val File.isSupported: Boolean + get() = true + + override fun fetch( + data: File, + resourceConfig: ResourceConfig + ): Flow> = flow { + val byteReadChannel = ByteReadChannel(data.availableData) + emit(Resource.Success(byteReadChannel, source)) + } + +} \ No newline at end of file diff --git a/kamel-core/src/darwinMain/kotlin/io/kamel/core/mapper/Mappers.kt b/kamel-core/src/darwinMain/kotlin/io/kamel/core/mapper/Mappers.kt new file mode 100644 index 00000000..99820f48 --- /dev/null +++ b/kamel-core/src/darwinMain/kotlin/io/kamel/core/mapper/Mappers.kt @@ -0,0 +1,25 @@ +package io.kamel.core.mapper + +import io.kamel.core.utils.URI +import io.kamel.core.utils.URL +import io.ktor.http.* +import kotlin.reflect.KClass + +internal actual val URLMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = URL::class + override val outputKClass: KClass + get() = Url::class + + override fun map(input: URL): Url = StringMapper.map(input.absoluteString()!!) +} + + +internal actual val URIMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = URI::class + override val outputKClass: KClass + get() = Url::class + + override fun map(input: URI): Url = StringMapper.map(input.uri) +} \ No newline at end of file diff --git a/kamel-core/src/darwinMain/kotlin/io/kamel/core/utils/Platform.kt b/kamel-core/src/darwinMain/kotlin/io/kamel/core/utils/Platform.kt new file mode 100644 index 00000000..a5565229 --- /dev/null +++ b/kamel-core/src/darwinMain/kotlin/io/kamel/core/utils/Platform.kt @@ -0,0 +1,44 @@ +package io.kamel.core.utils + +import kotlinx.cinterop.addressOf +import kotlinx.cinterop.usePinned +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import platform.Foundation.NSData +import platform.Foundation.NSFileHandle +import platform.Foundation.NSURL +import platform.Foundation.fileHandleForReadingAtPath +import platform.posix.memcpy + + +internal actual val Dispatchers.Kamel: CoroutineDispatcher get() = Default + +public actual class File(public val path: String) { + + private val fileHandle: NSFileHandle? = NSFileHandle.fileHandleForReadingAtPath(path) + public val availableData: ByteArray get() = fileHandle?.availableData?.toByteArray() ?: byteArrayOf() + override fun toString(): String = path +// memScoped { +// fileHandle ?: return@memScoped "null" +// println("File.toString()") +// val buffer = CharArray(MAXPATHLEN) { 0.toChar() } +// val result = buffer.usePinned { pinned -> +// fcntl(fileHandle.fileDescriptor, F_GETPATH, pinned.addressOf(0)) +// } +// println(result) +// return@memScoped buffer.joinToString("") +// } + + private fun NSData.toByteArray(): ByteArray = ByteArray(this@toByteArray.length.toInt()).apply { + usePinned { + memcpy(it.addressOf(0), this@toByteArray.bytes, this@toByteArray.length) + } + } + +} + +public actual class URL(public val nsUrl: NSURL) { + public fun absoluteString(): String? = nsUrl.absoluteString +} + +public actual class URI(public val uri: String) \ No newline at end of file diff --git a/kamel-core/src/darwinTest/kotlin/io/kamel/core/utils/MappersUtils.kt b/kamel-core/src/darwinTest/kotlin/io/kamel/core/utils/MappersUtils.kt new file mode 100644 index 00000000..584f9c59 --- /dev/null +++ b/kamel-core/src/darwinTest/kotlin/io/kamel/core/utils/MappersUtils.kt @@ -0,0 +1,8 @@ +package io.kamel.core.utils + +import platform.Foundation.NSURL + + +internal actual fun createURL(url: String): URL = URL(NSURL.URLWithString(url)!!) + +internal actual fun createURI(url: String): URI = URI(url) \ No newline at end of file diff --git a/kamel-core/src/jsMain/kotlin/io/kamel/core/fetcher/FileFetcher.kt b/kamel-core/src/jsMain/kotlin/io/kamel/core/fetcher/FileFetcher.kt new file mode 100644 index 00000000..c763f3b8 --- /dev/null +++ b/kamel-core/src/jsMain/kotlin/io/kamel/core/fetcher/FileFetcher.kt @@ -0,0 +1,54 @@ +package io.kamel.core.fetcher + +import io.kamel.core.DataSource +import io.kamel.core.Resource +import io.kamel.core.config.ResourceConfig +import io.kamel.core.utils.File +import io.ktor.utils.io.* +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.suspendCancellableCoroutine +import org.khronos.webgl.ArrayBuffer +import org.khronos.webgl.Int8Array +import org.w3c.dom.ErrorEvent +import org.w3c.files.FileReader +import kotlin.coroutines.resumeWithException +import kotlin.reflect.KClass + +/** + * Fetcher that fetchers [ByteReadChannel] from a file. + */ +internal actual object FileFetcher : Fetcher { + + override val inputDataKClass: KClass = File::class + + override val source: DataSource = DataSource.Disk + + override val File.isSupported: Boolean + get() = true + + @OptIn(ExperimentalCoroutinesApi::class) + override fun fetch( + data: File, + resourceConfig: ResourceConfig + ): Flow> = flow { + val byteReadChannel = ByteReadChannel(getBase64(data.file)) + emit(Resource.Success(byteReadChannel, source)) + } + + @ExperimentalCoroutinesApi + private suspend fun getBase64(file: org.w3c.files.File): ByteArray = suspendCancellableCoroutine { continuation -> + val reader = FileReader() + reader.readAsArrayBuffer(file) + reader.onload = { + val arrayBuffer = reader.result as ArrayBuffer + val bytes = Int8Array(arrayBuffer).unsafeCast() + continuation.resume(bytes, null) + } + reader.onerror = { error -> + continuation.resumeWithException(Error((error as ErrorEvent).message)) + } + } + +} \ No newline at end of file diff --git a/kamel-core/src/jsMain/kotlin/io/kamel/core/mapper/Mappers.kt b/kamel-core/src/jsMain/kotlin/io/kamel/core/mapper/Mappers.kt new file mode 100644 index 00000000..00bba534 --- /dev/null +++ b/kamel-core/src/jsMain/kotlin/io/kamel/core/mapper/Mappers.kt @@ -0,0 +1,25 @@ +package io.kamel.core.mapper + +import io.kamel.core.utils.URI +import io.kamel.core.utils.URL +import io.ktor.http.* +import kotlin.reflect.KClass + +internal actual val URLMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = URL::class + override val outputKClass: KClass + get() = Url::class + + override fun map(input: URL): Url = StringMapper.map(input.toString().removeSuffix("/")) +} + + +internal actual val URIMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = URI::class + override val outputKClass: KClass + get() = Url::class + + override fun map(input: URI): Url = StringMapper.map(input.uri) +} \ No newline at end of file diff --git a/kamel-core/src/jsMain/kotlin/io/kamel/core/utils/Platform.kt b/kamel-core/src/jsMain/kotlin/io/kamel/core/utils/Platform.kt new file mode 100644 index 00000000..7f094885 --- /dev/null +++ b/kamel-core/src/jsMain/kotlin/io/kamel/core/utils/Platform.kt @@ -0,0 +1,18 @@ +package io.kamel.core.utils + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + + +internal actual val Dispatchers.Kamel: CoroutineDispatcher get() = Default + +public actual class File(public val file: org.w3c.files.File) { + override fun toString(): String { + return file.name + } +} + + +public actual typealias URL = org.w3c.dom.url.URL + +public actual class URI(public val uri: String) \ No newline at end of file diff --git a/kamel-core/src/jsTest/kotlin/io/kamel/core/utils/MappersUtils.kt b/kamel-core/src/jsTest/kotlin/io/kamel/core/utils/MappersUtils.kt new file mode 100644 index 00000000..8f70f5e2 --- /dev/null +++ b/kamel-core/src/jsTest/kotlin/io/kamel/core/utils/MappersUtils.kt @@ -0,0 +1,7 @@ +package io.kamel.core.utils + + + +internal actual fun createURL(url: String): URL = URL(url) + +internal actual fun createURI(url: String): URI = URI(url) \ No newline at end of file diff --git a/kamel-core/src/jvmMain/kotlin/io/kamel/core/fetcher/JvmFileFetcher.kt b/kamel-core/src/jvmMain/kotlin/io/kamel/core/fetcher/JvmFileFetcher.kt index dd2d7fec..ca988386 100644 --- a/kamel-core/src/jvmMain/kotlin/io/kamel/core/fetcher/JvmFileFetcher.kt +++ b/kamel-core/src/jvmMain/kotlin/io/kamel/core/fetcher/JvmFileFetcher.kt @@ -8,12 +8,15 @@ import io.ktor.utils.io.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import java.io.File +import kotlin.reflect.KClass /** * Fetcher that fetchers [ByteReadChannel] from a file. */ internal actual object FileFetcher : Fetcher { + override val inputDataKClass: KClass = File::class + override val source: DataSource = DataSource.Disk override val File.isSupported: Boolean diff --git a/kamel-core/src/jvmMain/kotlin/io/kamel/core/mapper/JvmMappers.kt b/kamel-core/src/jvmMain/kotlin/io/kamel/core/mapper/JvmMappers.kt index 78e8e3f9..5fd23a9c 100644 --- a/kamel-core/src/jvmMain/kotlin/io/kamel/core/mapper/JvmMappers.kt +++ b/kamel-core/src/jvmMain/kotlin/io/kamel/core/mapper/JvmMappers.kt @@ -3,7 +3,22 @@ package io.kamel.core.mapper import io.kamel.core.utils.URI import io.kamel.core.utils.URL import io.ktor.http.* +import kotlin.reflect.KClass -internal actual val URLMapper: Mapper = Mapper { URIMapper.map(it.toURI()) } +internal actual val URLMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = URL::class + override val outputKClass: KClass + get() = Url::class -internal actual val URIMapper: Mapper = Mapper { Url(it) } \ No newline at end of file + override fun map(input: URL): Url = Url(input.toURI()) +} + +internal actual val URIMapper: Mapper = object : Mapper { + override val inputKClass: KClass + get() = URI::class + override val outputKClass: KClass + get() = Url::class + + override fun map(input: URI): Url = Url(input) +} \ No newline at end of file diff --git a/kamel-core/src/jvmMain/kotlin/io/kamel/core/utils/JvmPlatform.kt b/kamel-core/src/jvmMain/kotlin/io/kamel/core/utils/JvmPlatform.kt index 4df03255..29cde4b9 100644 --- a/kamel-core/src/jvmMain/kotlin/io/kamel/core/utils/JvmPlatform.kt +++ b/kamel-core/src/jvmMain/kotlin/io/kamel/core/utils/JvmPlatform.kt @@ -2,14 +2,13 @@ package io.kamel.core.utils import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers -import java.io.File import java.net.URI import java.net.URL -internal actual val Dispatchers.IO: CoroutineDispatcher get() = IO +internal actual val Dispatchers.Kamel: CoroutineDispatcher get() = IO -internal actual typealias File = File +public actual typealias File = java.io.File -internal actual typealias URL = URL +public actual typealias URL = URL -internal actual typealias URI = URI \ No newline at end of file +public actual typealias URI = URI \ No newline at end of file diff --git a/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/cache/LruCache.kt b/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/cache/LruCache.kt new file mode 100644 index 00000000..7cd3a565 --- /dev/null +++ b/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/cache/LruCache.kt @@ -0,0 +1,26 @@ +package io.kamel.core.cache + + +/** + * Cache implementation which evicts items using an LRU algorithm. + */ +internal actual class LruCache actual constructor(override val maxSize: Int) : Cache { + + private val cache: io.kamel.core.cache.common.LruCache = io.kamel.core.cache.common.LruCache(maxSize) + + override val size: Int + get() = cache.size() + + init { + require(maxSize >= 0) { "Cache max size must be positive number" } + } + + override fun get(key: K): V? = cache[key] + + override fun set(key: K, value: V) = cache.set(key, value) + + override fun remove(key: K): Boolean = cache.remove(key) != null + + override fun clear(): Unit = cache.clear() + +} \ No newline at end of file diff --git a/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/cache/common/LruCache.kt b/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/cache/common/LruCache.kt new file mode 100644 index 00000000..aa0f16fa --- /dev/null +++ b/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/cache/common/LruCache.kt @@ -0,0 +1,161 @@ +package io.kamel.core.cache.common + +internal typealias Weigher = (Key, Value?) -> Int + +/** + * Multiplatform LRU cache implementation. + * https://github.com/apollographql/apollo-kotlin/blob/main/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/api/internal/LruCache.kt + * + * Implementation is based on usage of [LinkedHashMap] as a container for the cache and custom + * double linked queue to track LRU property. + * + * [maxSize] - maximum size of the cache, can be anything bytes, number of entries etc. By default is number o entries. + * [weigher] - to be called to calculate the estimated size (weight) of the cache entry defined by its [Key] and [Value]. + * By default it returns 1. + * + * Cache trim performed only on new entry insertion. + */ +internal class LruCache( + private val maxSize: Int, + private val weigher: Weigher = { _, _ -> 1 }, +) { + private val cache = LinkedHashMap>(0, 0.75f) + private var headNode: Node? = null + private var tailNode: Node? = null + private var size: Int = 0 + + operator fun get(key: Key): Value? { + val node = cache[key] + if (node != null) { + moveNodeToHead(node) + } + return node?.value + } + + operator fun set(key: Key, value: Value) { + val node = cache[key] + if (node == null) { + cache[key] = addNode(key, value) + } else { + node.value = value + moveNodeToHead(node) + } + + trim() + } + + fun remove(key: Key): Value? { + return removeUnsafe(key) + } + + fun keys() = cache.keys + + private fun removeUnsafe(key: Key): Value? { + val nodeToRemove = cache.remove(key) + val value = nodeToRemove?.value + if (nodeToRemove != null) { + unlinkNode(nodeToRemove) + } + return value + } + + fun remove(keys: Collection) { + keys.forEach { key -> removeUnsafe(key) } + } + + fun clear() { + cache.clear() + headNode = null + tailNode = null + size = 0 + } + + fun size(): Int { + return size + } + + fun dump(): Map { + return cache.mapValues { (_, value) -> + @Suppress("UNCHECKED_CAST") + value.value as Value + } + } + + private fun trim() { + var nodeToRemove = tailNode + while (nodeToRemove != null && size > maxSize) { + cache.remove(nodeToRemove.key) + unlinkNode(nodeToRemove) + nodeToRemove = tailNode + } + } + + private fun addNode(key: Key, value: Value?): Node { + val node = Node( + key = key, + value = value, + next = headNode, + prev = null, + ) + + headNode = node + + if (node.next == null) { + tailNode = headNode + } else { + node.next?.prev = headNode + } + + size += weigher(key, value) + + return node + } + + private fun moveNodeToHead(node: Node) { + if (node.prev == null) { + return + } + + node.prev?.next = node.next + + if (node.next == null) { + tailNode = node.prev + } else { + node.next?.prev = node.prev + } + + node.next = headNode + node.prev = null + + headNode?.prev = node + headNode = node + } + + private fun unlinkNode(node: Node) { + if (node.prev == null) { + this.headNode = node.next + } else { + node.prev?.next = node.next + } + + if (node.next == null) { + this.tailNode = node.prev + } else { + node.next?.prev = node.prev + } + + size -= weigher(node.key!!, node.value) + + node.key = null + node.value = null + node.next = null + node.prev = null + } + + private class Node( + var key: Key?, + var value: Value?, + var next: Node?, + var prev: Node?, + ) +} \ No newline at end of file diff --git a/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/utils/ConfigUtils.kt b/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/utils/ConfigUtils.kt new file mode 100644 index 00000000..7ae031e8 --- /dev/null +++ b/kamel-core/src/nonJvmMain/kotlin/io/kamel/core/utils/ConfigUtils.kt @@ -0,0 +1,41 @@ +@file:Suppress("UNCHECKED_CAST") + +package io.kamel.core.utils + +import io.kamel.core.config.KamelConfig +import io.kamel.core.decoder.Decoder +import io.kamel.core.fetcher.Fetcher + +internal actual fun KamelConfig.findFetcherFor(data: T): Fetcher { + + val type = data::class + + val fetcher = fetchers.findLast { fetcher -> + + val fetcherType = fetcher.inputDataKClass + + val isSameType = fetcherType == type + + isSameType && with(fetcher) { data.isSupported } + } + + checkNotNull(fetcher) { "Unable to find a fetcher for $type" } + + return fetcher as Fetcher +} + +internal actual inline fun KamelConfig.findDecoderFor(): Decoder { + + val type = T::class + + val decoder = decoders.findLast { decoder -> + + val decoderType = decoder.outputKClass + + decoderType == type + } + + checkNotNull(decoder) { "Unable to find a decoder for $type" } + + return decoder as Decoder +} diff --git a/kamel-image/build.gradle.kts b/kamel-image/build.gradle.kts index 7a616cfb..5b658e6a 100644 --- a/kamel-image/build.gradle.kts +++ b/kamel-image/build.gradle.kts @@ -1,4 +1,3 @@ -import org.jetbrains.compose.compose import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode plugins { @@ -14,13 +13,12 @@ android { defaultConfig { minSdk = 21 - targetSdk = 33 multiDexEnabled = true } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } testOptions { @@ -29,22 +27,6 @@ android { } } - sourceSets { - named("main") { - manifest.srcFile("src/androidMain/AndroidManifest.xml") - res.srcDirs("src/androidMain/res", "src/commonMain/resources") - } - } - - configurations { - create("androidTestApi") - create("androidTestDebugApi") - create("androidTestReleaseApi") - create("testApi") - create("testDebugApi") - create("testReleaseApi") - } - } kotlin { @@ -55,59 +37,115 @@ kotlin { publishAllLibraryVariants() } jvm("desktop") + js(IR) { + browser() + } + for (target in Targets.nativeTargets) { + targets.add(presets.getByName(target).createTarget(target)) + } sourceSets { val commonMain by getting { dependencies { api(project(":kamel-core")) + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.runtime) } } val commonTest by getting { dependencies { implementation(project(":kamel-tests")) - implementation(kotlin("test-common")) - implementation(kotlin("test-annotations-common")) + implementation(kotlin("test")) implementation(Dependencies.Testing.Ktor) + implementation(Dependencies.Coroutines.Test) + } + } + + val jvmMain by creating { + dependsOn(commonMain) + } + + val jvmTest by creating { + dependsOn(commonTest) + dependencies { + implementation(compose.material) implementation(Dependencies.Testing.Compose) } } - val desktopMain by getting + val desktopMain by getting { + dependsOn(jvmMain) + } val desktopTest by getting { + dependsOn(jvmTest) dependencies { implementation(Dependencies.Ktor.CIO) implementation(compose.desktop.currentOs) - implementation(kotlin("test-junit")) } } - val androidMain by getting + val androidMain by getting { + dependsOn(jvmMain) + } - val androidTest by getting { + val androidUnitTest by getting { + dependsOn(jvmTest) + } + + val nonJvmMain by creating { + dependsOn(commonMain) dependencies { - implementation(kotlin("test")) - implementation(kotlin("test-junit")) - implementation("androidx.test:core:1.4.0") - implementation("androidx.test.ext:junit:1.1.3") + implementation(Dependencies.XmlUtil.Serialization) } } - all { - languageSettings.apply { - optIn("kotlin.Experimental") + val nonJvmTest by creating { + dependsOn(commonTest) + } + + val jsMain by getting { + dependsOn(nonJvmMain) + dependencies { + implementation(Dependencies.Ktor.Js) + } + } + + val darwinMain by creating { + dependsOn(nonJvmMain) + dependencies { + implementation(Dependencies.Ktor.Darwin) } } - targets.all { - compilations.all { - kotlinOptions { - freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn") - } + val darwinTest by creating { + dependsOn(nonJvmTest) + } + + Targets.darwinTargets.forEach { target -> + getByName("${target}Main") { + dependsOn(darwinMain) + } + getByName("${target}Test") { + dependsOn(darwinTest) + } + } + + all { + languageSettings.apply { + optIn("kotlin.Experimental") } } } } + +// https://youtrack.jetbrains.com/issue/KT-46466 +val dependsOnTasks = mutableListOf() +tasks.withType().configureEach { + dependsOnTasks.add(this.name.replace("publish", "sign").replaceAfter("Publication", "")) + dependsOn(dependsOnTasks) +} \ No newline at end of file diff --git a/kamel-image/src/androidMain/kotlin/io/kamel/image/decoder/AndroidImageBitmapDecoder.kt b/kamel-image/src/androidMain/kotlin/io/kamel/image/decoder/AndroidImageBitmapDecoder.kt index f395209c..3edda718 100644 --- a/kamel-image/src/androidMain/kotlin/io/kamel/image/decoder/AndroidImageBitmapDecoder.kt +++ b/kamel-image/src/androidMain/kotlin/io/kamel/image/decoder/AndroidImageBitmapDecoder.kt @@ -8,11 +8,14 @@ import io.kamel.core.config.ResourceConfig import io.kamel.core.decoder.Decoder import io.ktor.util.* import io.ktor.utils.io.* +import kotlin.reflect.KClass private const val Offset = 0 internal actual object ImageBitmapDecoder : Decoder { + override val outputKClass: KClass = ImageBitmap::class + override suspend fun decode(channel: ByteReadChannel, resourceConfig: ResourceConfig): ImageBitmap { val bytes = channel.toByteArray() val bitmap = BitmapFactory.decodeByteArray(bytes, Offset, bytes.size) as Bitmap diff --git a/kamel-image/src/androidMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt b/kamel-image/src/androidMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt index 212a1835..849aa2d1 100644 --- a/kamel-image/src/androidMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt +++ b/kamel-image/src/androidMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt @@ -12,10 +12,13 @@ import io.ktor.utils.io.* import io.ktor.utils.io.jvm.javaio.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import kotlin.reflect.KClass internal class ResourcesFetcher(private val context: Context) : Fetcher { + override val inputDataKClass: KClass = Url::class + override val source: DataSource = DataSource.Disk override val Url.isSupported: Boolean diff --git a/kamel-image/src/androidMain/kotlin/io/kamel/image/mapper/ResourcesIdMapper.kt b/kamel-image/src/androidMain/kotlin/io/kamel/image/mapper/ResourcesIdMapper.kt index caf2650f..1973c1f6 100644 --- a/kamel-image/src/androidMain/kotlin/io/kamel/image/mapper/ResourcesIdMapper.kt +++ b/kamel-image/src/androidMain/kotlin/io/kamel/image/mapper/ResourcesIdMapper.kt @@ -5,10 +5,17 @@ import android.content.Context import androidx.annotation.DrawableRes import io.kamel.core.mapper.Mapper import io.ktor.http.* +import kotlin.reflect.KClass internal class ResourcesIdMapper(private val context: Context) : Mapper<@receiver:DrawableRes Int, Url> { + override val inputKClass: KClass + get() = Int::class + + override val outputKClass: KClass + get() = Url::class + override fun map(@DrawableRes input: Int): Url { val packageName = context.packageName val protocol = URLProtocol(name = ContentResolver.SCHEME_ANDROID_RESOURCE, defaultPort = -1) diff --git a/kamel-image/src/commonMain/kotlin/io/kamel/image/LazyPainterResource.kt b/kamel-image/src/commonMain/kotlin/io/kamel/image/LazyPainterResource.kt index b86326c4..49f9d57a 100644 --- a/kamel-image/src/commonMain/kotlin/io/kamel/image/LazyPainterResource.kt +++ b/kamel-image/src/commonMain/kotlin/io/kamel/image/LazyPainterResource.kt @@ -15,6 +15,8 @@ import io.kamel.core.config.ResourceConfigBuilder import io.kamel.image.config.LocalKamelConfig import io.ktor.http.* +public class PainterFailure : Error("Failed to return a Painter") + /** * Loads a [Painter] resource asynchronously. * @param data Can be anything such as [String], [Url] or a [File]. @@ -32,13 +34,13 @@ import io.ktor.http.* */ @ExperimentalKamelApi @Composable -public inline fun lazyPainterResource( - data: Any, +public inline fun lazyPainterResource( + data: I, key: Any? = data, filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, - noinline onLoadingPainter: @Composable (Float) -> Painter? = { null }, - noinline onFailurePainter: @Composable (Throwable) -> Painter? = { null }, - block: ResourceConfigBuilder.() -> Unit = {}, + noinline onLoadingPainter: @Composable (Float) -> Result = { Result.failure(PainterFailure()) }, + noinline onFailurePainter: @Composable (Throwable) -> Result = { Result.failure(PainterFailure()) }, + crossinline block: ResourceConfigBuilder.() -> Unit = {}, ): Resource { val kamelConfig = LocalKamelConfig.current @@ -61,14 +63,17 @@ public inline fun lazyPainterResource( val painterResourceWithFallbacks = when (painterResource) { is Resource.Loading -> { val resource = painterResource as Resource.Loading - val painter = onLoadingPainter(resource.progress) - if (painter != null) Resource.Success(painter) else painterResource + onLoadingPainter(resource.progress) + .mapCatching { painter -> Resource.Success(painter) } + .getOrDefault(painterResource) } + is Resource.Success -> painterResource is Resource.Failure -> { val resource = painterResource as Resource.Failure - val painter = onFailurePainter(resource.exception) - if (painter != null) Resource.Success(painter) else painterResource + onFailurePainter(resource.exception) + .mapCatching { painter -> Resource.Success(painter) } + .getOrDefault(painterResource) } } @@ -83,6 +88,7 @@ public inline fun lazyPainterResource( } } + /** * Loads a [Painter] resource asynchronously. * @param data Can be anything such as [String], [Url] or a [File]. @@ -98,12 +104,12 @@ public inline fun lazyPainterResource( data: Any, key: Any? = data, filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, - block: ResourceConfigBuilder.() -> Unit = {}, + crossinline block: ResourceConfigBuilder.() -> Unit = {}, ): Resource = lazyPainterResource( data, key, filterQuality, - onLoadingPainter = { null }, - onFailurePainter = { null }, + onLoadingPainter = { Result.failure(PainterFailure()) }, + onFailurePainter = { Result.failure(PainterFailure()) }, block ) \ No newline at end of file diff --git a/kamel-image/src/darwinMain/kotlin/attributeOrNull.kt b/kamel-image/src/darwinMain/kotlin/attributeOrNull.kt new file mode 100644 index 00000000..1085ca54 --- /dev/null +++ b/kamel-image/src/darwinMain/kotlin/attributeOrNull.kt @@ -0,0 +1,15 @@ +import nl.adaptivity.xmlutil.dom.Element + +/*** + * Accessing by namespace does not appear to be working with https://github.com/pdvrieze/xmlutil v0.86.0 + * note: on native ":" had to be prepended to name to load attributes 🤷‍ + * todo: figure out how to handle namespaces + */ +internal actual fun Element.attributeOrNull( + @Suppress("UNUSED_PARAMETER") namespace: String, + name: String +): String? { +// val value = getAttributeNS(namespace,":$name") + val value = getAttribute(":$name") + return value?.ifBlank { null } +} \ No newline at end of file diff --git a/kamel-image/src/darwinMain/kotlin/filterIsElement.kt b/kamel-image/src/darwinMain/kotlin/filterIsElement.kt new file mode 100644 index 00000000..c0edaa22 --- /dev/null +++ b/kamel-image/src/darwinMain/kotlin/filterIsElement.kt @@ -0,0 +1,5 @@ +import nl.adaptivity.xmlutil.dom.Element +import nl.adaptivity.xmlutil.dom.Node + +internal actual fun Sequence.filterIsElement(): Sequence = + filterIsInstance() \ No newline at end of file diff --git a/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageBitmapDecoder.kt b/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageBitmapDecoder.kt index 702decee..5d2c6c6f 100644 --- a/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageBitmapDecoder.kt +++ b/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageBitmapDecoder.kt @@ -7,12 +7,15 @@ import io.kamel.core.decoder.Decoder import io.ktor.util.* import io.ktor.utils.io.* import org.jetbrains.skia.Image +import kotlin.reflect.KClass /** * Decodes and transfers [ByteReadChannel] to [ImageBitmap] using Skia [Image]. */ internal actual object ImageBitmapDecoder : Decoder { + override val outputKClass: KClass = ImageBitmap::class + override suspend fun decode( channel: ByteReadChannel, resourceConfig: ResourceConfig diff --git a/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageVectorDecoder.kt b/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageVectorDecoder.kt index eba171d2..0cc0cae2 100644 --- a/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageVectorDecoder.kt +++ b/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopImageVectorDecoder.kt @@ -1,5 +1,6 @@ package io.kamel.image.decoder +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.loadXmlImageVector import io.kamel.core.config.ResourceConfig @@ -7,8 +8,12 @@ import io.kamel.core.decoder.Decoder import io.ktor.utils.io.* import io.ktor.utils.io.jvm.javaio.* import org.xml.sax.InputSource +import kotlin.reflect.KClass internal object ImageVectorDecoder : Decoder { + + override val outputKClass: KClass = ImageVector::class + override suspend fun decode(channel: ByteReadChannel, resourceConfig: ResourceConfig): ImageVector { val inputSource = InputSource(channel.toInputStream()) return loadXmlImageVector(inputSource, resourceConfig.density) diff --git a/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopSvgDecoder.kt b/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopSvgDecoder.kt index bbb7f263..16ce2fae 100644 --- a/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopSvgDecoder.kt +++ b/kamel-image/src/desktopMain/kotlin/io/kamel/image/decoder/DesktopSvgDecoder.kt @@ -1,13 +1,18 @@ package io.kamel.image.decoder import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.loadSvgPainter import io.kamel.core.config.ResourceConfig import io.kamel.core.decoder.Decoder import io.ktor.utils.io.* import io.ktor.utils.io.jvm.javaio.* +import kotlin.reflect.KClass internal object SvgDecoder : Decoder { + + override val outputKClass: KClass = Painter::class + override suspend fun decode(channel: ByteReadChannel, resourceConfig: ResourceConfig): Painter { return loadSvgPainter( channel.toInputStream(), diff --git a/kamel-image/src/desktopMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt b/kamel-image/src/desktopMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt index a76794eb..4c0e2d76 100644 --- a/kamel-image/src/desktopMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt +++ b/kamel-image/src/desktopMain/kotlin/io/kamel/image/fetcher/ResourcesFetcher.kt @@ -9,9 +9,12 @@ import io.ktor.http.* import io.ktor.utils.io.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import kotlin.reflect.KClass internal object ResourcesFetcher : Fetcher { + override val inputDataKClass: KClass = Url::class + override val source: DataSource = DataSource.Disk override val Url.isSupported: Boolean diff --git a/kamel-image/src/desktopTest/kotlin/io/kamel/image/fetcher/ResourcesFetcherTest.kt b/kamel-image/src/desktopTest/kotlin/io/kamel/image/fetcher/ResourcesFetcherTest.kt index 98e8acc1..637a57b7 100644 --- a/kamel-image/src/desktopTest/kotlin/io/kamel/image/fetcher/ResourcesFetcherTest.kt +++ b/kamel-image/src/desktopTest/kotlin/io/kamel/image/fetcher/ResourcesFetcherTest.kt @@ -22,15 +22,15 @@ class ResourcesFetcherTest { private val resourceConfig = ResourceConfigBuilder().build() @Test - fun testUrlIsSupported(): Unit = runTest { - val imageUrl = Url("Compose.png") + fun testUrlIsSupported() = runTest { + val imageUrl = Url("files/Compose.png") val isSupported = with(fetcher) { imageUrl.isSupported } assertTrue { isSupported } } @Test - fun testUrlIsNotSupported(): Unit = runTest { + fun testUrlIsNotSupported() = runTest { val imageUrl = Url("invalidImage.jpg") val isSupported = with(fetcher) { imageUrl.isSupported } @@ -38,8 +38,8 @@ class ResourcesFetcherTest { } @Test - fun loadImageBitmapResource(): Unit = runTest { - val imageUrl = Url("Compose.png") + fun loadImageBitmapResource() = runTest { + val imageUrl = Url("files/Compose.png") val resource = fetcher.fetch(imageUrl, resourceConfig) .first { !it.isLoading } .map { it.toByteArray() } @@ -49,7 +49,7 @@ class ResourcesFetcherTest { } @Test - fun loadInvalidImageResource(): Unit = runTest { + fun loadInvalidImageResource() = runTest { val imageUrl = Url("invalidImage.jpg") assertFailsWith { diff --git a/kamel-image/src/jsMain/kotlin/attributeOrNull.kt b/kamel-image/src/jsMain/kotlin/attributeOrNull.kt new file mode 100644 index 00000000..927c508e --- /dev/null +++ b/kamel-image/src/jsMain/kotlin/attributeOrNull.kt @@ -0,0 +1,15 @@ +import nl.adaptivity.xmlutil.dom.Element + +/*** + * Accessing by namespace does not appear to be working with https://github.com/pdvrieze/xmlutil v0.86.0 + * note: on native ":" had to be prepended to name to load attributes 🤷‍ + * todo: figure out how to handle namespaces + */ +internal actual fun Element.attributeOrNull( + @Suppress("UNUSED_PARAMETER") namespace: String, + name: String +): String? { +// val value = getAttributeNS(namespace, name) + val value = getAttribute(name) + return value?.ifBlank { null } +} \ No newline at end of file diff --git a/kamel-image/src/jsMain/kotlin/filterIsElement.kt b/kamel-image/src/jsMain/kotlin/filterIsElement.kt new file mode 100644 index 00000000..ff73947a --- /dev/null +++ b/kamel-image/src/jsMain/kotlin/filterIsElement.kt @@ -0,0 +1,9 @@ +import nl.adaptivity.js.util.asElement +import nl.adaptivity.xmlutil.dom.Element +import nl.adaptivity.xmlutil.dom.Node + +@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE") +internal actual fun Sequence.filterIsElement(): Sequence = + mapNotNull { + (it as org.w3c.dom.Node).asElement() as Element? + } \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/DrawCache.kt b/kamel-image/src/nonJvmMain/kotlin/DrawCache.kt new file mode 100644 index 00000000..58c83b0e --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/DrawCache.kt @@ -0,0 +1,91 @@ +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.Canvas +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.drawscope.CanvasDrawScope +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.toSize + +/** + * Creates a drawing environment that directs its drawing commands to an [ImageBitmap] + * which can be drawn directly in another [DrawScope] instance. This is useful to cache + * complicated drawing commands across frames especially if the content has not changed. + * Additionally some drawing operations such as rendering paths are done purely in + * software so it is beneficial to cache the result and render the contents + * directly through a texture as done by [DrawScope.drawImage] + */ +// Note copied from here: +// https://github.com/JetBrains/compose-multiplatform-core/blob/5c26b7b9f5619ee4f319c6caf43192851b8ee15e/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/DrawCache.kt#L39 +// todo: remove when available in common androidx +internal class DrawCache { + + @PublishedApi internal var mCachedImage: ImageBitmap? = null + private var cachedCanvas: Canvas? = null + private var scopeDensity: Density? = null + private var layoutDirection: LayoutDirection = LayoutDirection.Ltr + private var size: IntSize = IntSize.Zero + + private val cacheScope = CanvasDrawScope() + + /** + * Draw the contents of the lambda with receiver scope into an [ImageBitmap] with the provided + * size. If the same size is provided across calls, the same [ImageBitmap] instance is + * re-used and the contents are cleared out before drawing content in it again + */ + fun drawCachedImage( + size: IntSize, + density: Density, + layoutDirection: LayoutDirection, + block: DrawScope.() -> Unit + ) { + this.scopeDensity = density + this.layoutDirection = layoutDirection + var targetImage = mCachedImage + var targetCanvas = cachedCanvas + if (targetImage == null || + targetCanvas == null || + size.width > targetImage.width || + size.height > targetImage.height + ) { + targetImage = ImageBitmap(size.width, size.height) + targetCanvas = Canvas(targetImage) + + mCachedImage = targetImage + cachedCanvas = targetCanvas + } + this.size = size + cacheScope.draw(density, layoutDirection, targetCanvas, size.toSize()) { + clear() + block() + } + targetImage.prepareToDraw() + } + + /** + * Draw the cached content into the provided [DrawScope] instance + */ + fun drawInto( + target: DrawScope, + alpha: Float = 1.0f, + colorFilter: ColorFilter? = null + ) { + val targetImage = mCachedImage + check(targetImage != null) { + "drawCachedImage must be invoked first before attempting to draw the result " + + "into another destination" + } + target.drawImage(targetImage, srcSize = size, alpha = alpha, colorFilter = colorFilter) + } + + /** + * Helper method to clear contents of the draw environment from the given bounds of the + * DrawScope + */ + private fun DrawScope.clear() { + drawRect(color = Color.Black, blendMode = BlendMode.Clear) + } +} \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/ValueParsers.kt b/kamel-image/src/nonJvmMain/kotlin/ValueParsers.kt new file mode 100644 index 00000000..4f259529 --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/ValueParsers.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.TileMode +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +// copied from +// https://github.com/JetBrains/compose-multiplatform-core/blob/5c26b7b9f5619ee4f319c6caf43192851b8ee15e/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/res/vector/DesktopValueParsers.desktop.kt#L29 + +private const val ALPHA_MASK = 0xFF000000.toInt() + +// parseColorValue is copied from Android: +// https://cs.android.com/android-studio/platform/tools/base/+/05fadd8cb2aaafb77da02048c7a240b2147ff293:sdk-common/src/main/java/com/android/ide/common/vectordrawable/VdUtil.kt;l=58 +/** + * Parses a color value in #AARRGGBB format. + * + * @param color the color value string + * @return the integer color value + */ +internal fun parseColorValue(color: String): Int { + require(color.startsWith("#")) { "Invalid color value $color" } + + return when (color.length) { + 7 -> { + // #RRGGBB + color.substring(1).toUInt( 16).toInt() or ALPHA_MASK + } + 9 -> { + // #AARRGGBB + color.substring(1).toUInt( 16).toInt() + } + 4 -> { + // #RGB + val v = color.substring(1).toUInt( 16).toInt() + var k = (v shr 8 and 0xF) * 0x110000 + k = k or (v shr 4 and 0xF) * 0x1100 + k = k or (v and 0xF) * 0x11 + k or ALPHA_MASK + } + 5 -> { + // #ARGB + val v = color.substring(1).toUInt( 16).toInt() + var k = (v shr 12 and 0xF) * 0x11000000 + k = k or (v shr 8 and 0xF) * 0x110000 + k = k or (v shr 4 and 0xF) * 0x1100 + k = k or (v and 0xF) * 0x11 + k or ALPHA_MASK + } + else -> ALPHA_MASK + } +} + +internal fun parseFillType(fillType: String): PathFillType = when (fillType) { + "nonZero" -> PathFillType.NonZero + "evenOdd" -> PathFillType.EvenOdd + else -> throw UnsupportedOperationException("unknown fillType: $fillType") +} + +internal fun parseStrokeCap(strokeCap: String): StrokeCap = when (strokeCap) { + "butt" -> StrokeCap.Butt + "round" -> StrokeCap.Round + "square" -> StrokeCap.Square + else -> throw UnsupportedOperationException("unknown strokeCap: $strokeCap") +} + +internal fun parseStrokeJoin(strokeJoin: String): StrokeJoin = when (strokeJoin) { + "miter" -> StrokeJoin.Miter + "round" -> StrokeJoin.Round + "bevel" -> StrokeJoin.Bevel + else -> throw UnsupportedOperationException("unknown strokeJoin: $strokeJoin") +} + +internal fun parseTileMode(tileMode: String): TileMode = when (tileMode) { + "clamp" -> TileMode.Clamp + "repeated" -> TileMode.Repeated + "mirror" -> TileMode.Mirror + else -> throw throw UnsupportedOperationException("unknown tileMode: $tileMode") +} + +internal fun String?.parseDp(density: Density): Dp = with(density) { + return when { + this@parseDp == null -> 0f.dp + endsWith("dp") -> removeSuffix("dp").toFloat().dp + endsWith("px") -> removeSuffix("px").toFloat().toDp() + else -> throw UnsupportedOperationException("value should ends with dp or px") + } +} \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/XmlVectorParser.kt b/kamel-image/src/nonJvmMain/kotlin/XmlVectorParser.kt new file mode 100644 index 00000000..8a526b4b --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/XmlVectorParser.kt @@ -0,0 +1,264 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.vector.* +import androidx.compose.ui.unit.Density +import nl.adaptivity.xmlutil.dom.* + +// Parsing logic is the same as in Android implementation +// (compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/graphics/vector/compat/XmlVectorParser.kt) +// +// Except there is no support for linking with external resources +// (for example, we can't reference to color defined in another file) +// +// Specification: +// https://developer.android.com/reference/android/graphics/drawable/VectorDrawable + +// ported from +// https://github.com/JetBrains/compose-multiplatform-core/blob/5c26b7b9f5619ee4f319c6caf43192851b8ee15e/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/res/vector/DesktopXmlVectorParser.desktop.kt#L72 +// to use https://github.com/pdvrieze/xmlutil + +private const val ANDROID_NS = "http://schemas.android.com/apk/res/android" +private const val AAPT_NS = "http://schemas.android.com/aapt" + +private class BuildContext { + val currentGroups = mutableListOf() + + enum class Group { + /** + * Group that exists in xml file + */ + Real, + + /** + * Group that doesn't exist in xml file. We add it manually when we see node. + * It will be automatically popped when the real group will be popped. + */ + Virtual + } +} + +internal fun Element.parseVectorRoot(density: Density): ImageVector { + val context = BuildContext() + val builder = ImageVector.Builder( + defaultWidth = attributeOrNull(ANDROID_NS, "width").parseDp(density), + defaultHeight = attributeOrNull(ANDROID_NS, "height").parseDp(density), + viewportWidth = attributeOrNull(ANDROID_NS, "viewportWidth")?.toFloat() ?: 0f, + viewportHeight = attributeOrNull(ANDROID_NS, "viewportHeight")?.toFloat() ?: 0f + ) + parseVectorNodes(builder, context) + return builder.build() +} + +private fun Element.parseVectorNodes(builder: ImageVector.Builder, context: BuildContext) { + childrenSequence + .filterIsElement() + .forEach { + it.parseVectorNode(builder, context) + } +} + +private fun Element.parseVectorNode(builder: ImageVector.Builder, context: BuildContext) { + when (nodeName) { + "path" -> parsePath(builder) + "clip-path" -> parseClipPath(builder, context) + "group" -> parseGroup(builder, context) + } +} + +private fun Element.parsePath(builder: ImageVector.Builder) { + builder.addPath( + pathData = addPathNodes(attributeOrNull(ANDROID_NS, "pathData")), + pathFillType = attributeOrNull(ANDROID_NS, "fillType") + ?.let(::parseFillType) ?: PathFillType.NonZero, + name = attributeOrNull(ANDROID_NS, "name") ?: "", + fill = attributeOrNull(ANDROID_NS, "fillColor")?.let(::parseStringBrush) + ?: apptAttr(ANDROID_NS, "fillColor")?.let(Element::parseElementBrush), + fillAlpha = attributeOrNull(ANDROID_NS, "fillAlpha")?.toFloat() ?: 1.0f, + stroke = attributeOrNull(ANDROID_NS, "strokeColor")?.let(::parseStringBrush) + ?: apptAttr(ANDROID_NS, "strokeColor")?.let(Element::parseElementBrush), + strokeAlpha = attributeOrNull(ANDROID_NS, "strokeAlpha")?.toFloat() ?: 1.0f, + strokeLineWidth = attributeOrNull(ANDROID_NS, "strokeWidth")?.toFloat() ?: 1.0f, + strokeLineCap = attributeOrNull(ANDROID_NS, "strokeLineCap") + ?.let(::parseStrokeCap) ?: StrokeCap.Butt, + strokeLineJoin = attributeOrNull(ANDROID_NS, "strokeLineJoin") + ?.let(::parseStrokeJoin) ?: StrokeJoin.Miter, + strokeLineMiter = attributeOrNull(ANDROID_NS, "strokeMiterLimit")?.toFloat() ?: 1.0f, + trimPathStart = attributeOrNull(ANDROID_NS, "trimPathStart")?.toFloat() ?: 0.0f, + trimPathEnd = attributeOrNull(ANDROID_NS, "trimPathEnd")?.toFloat() ?: 1.0f, + trimPathOffset = attributeOrNull(ANDROID_NS, "trimPathOffset")?.toFloat() ?: 0.0f + ) +} + +private fun Element.parseClipPath(builder: ImageVector.Builder, context: BuildContext) { + builder.addGroup( + name = attributeOrNull(ANDROID_NS, "name") ?: "", + clipPathData = addPathNodes(attributeOrNull(ANDROID_NS, "pathData")) + ) + context.currentGroups.add(BuildContext.Group.Virtual) +} + +private fun Element.parseGroup(builder: ImageVector.Builder, context: BuildContext) { + builder.addGroup( + attributeOrNull(ANDROID_NS, "name") ?: "", + attributeOrNull(ANDROID_NS, "rotation")?.toFloat() ?: DefaultRotation, + attributeOrNull(ANDROID_NS, "pivotX")?.toFloat() ?: DefaultPivotX, + attributeOrNull(ANDROID_NS, "pivotY")?.toFloat() ?: DefaultPivotY, + attributeOrNull(ANDROID_NS, "scaleX")?.toFloat() ?: DefaultScaleX, + attributeOrNull(ANDROID_NS, "scaleY")?.toFloat() ?: DefaultScaleY, + attributeOrNull(ANDROID_NS, "translateX")?.toFloat() ?: DefaultTranslationX, + attributeOrNull(ANDROID_NS, "translateY")?.toFloat() ?: DefaultTranslationY, + EmptyPath + ) + context.currentGroups.add(BuildContext.Group.Real) + + parseVectorNodes(builder, context) + + do { + val removedGroup = context.currentGroups.removeLastOrNull() + builder.clearGroup() + } while (removedGroup == BuildContext.Group.Virtual) +} + +private fun parseStringBrush(str: String) = SolidColor(Color(parseColorValue(str))) + +private fun Element.parseElementBrush(): Brush? = + childrenSequence + .filterIsElement() + .find { it.nodeName == "gradient" } + ?.parseGradient() + +private fun Element.parseGradient(): Brush? { + return when (attributeOrNull(ANDROID_NS, "type")) { + "linear" -> parseLinearGradient() + "radial" -> parseRadialGradient() + "sweep" -> parseSweepGradient() + else -> null + } +} + +@Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS") +private fun Element.parseLinearGradient() = Brush.linearGradient( + colorStops = parseColorStops(), + start = Offset( + attributeOrNull(ANDROID_NS, "startX")?.toFloat() ?: 0f, + attributeOrNull(ANDROID_NS, "startY")?.toFloat() ?: 0f + ), + end = Offset( + attributeOrNull(ANDROID_NS, "endX")?.toFloat() ?: 0f, + attributeOrNull(ANDROID_NS, "endY")?.toFloat() ?: 0f + ), + tileMode = attributeOrNull(ANDROID_NS, "tileMode")?.let(::parseTileMode) ?: TileMode.Clamp +) + +@Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS") +private fun Element.parseRadialGradient() = Brush.radialGradient( + colorStops = parseColorStops(), + center = Offset( + attributeOrNull(ANDROID_NS, "centerX")?.toFloat() ?: 0f, + attributeOrNull(ANDROID_NS, "centerY")?.toFloat() ?: 0f + ), + radius = attributeOrNull(ANDROID_NS, "gradientRadius")?.toFloat() ?: 0f, + tileMode = attributeOrNull(ANDROID_NS, "tileMode")?.let(::parseTileMode) ?: TileMode.Clamp +) + +@Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS") +private fun Element.parseSweepGradient() = Brush.sweepGradient( + colorStops = parseColorStops(), + center = Offset( + attributeOrNull(ANDROID_NS, "centerX")?.toFloat() ?: 0f, + attributeOrNull(ANDROID_NS, "centerY")?.toFloat() ?: 0f, + ) +) + +private fun Element.parseColorStops(): Array> { + val items = childrenSequence + .filterIsElement() + .filter { it.nodeName == "item" } + .toList() + + val colorStops = items.mapIndexedNotNullTo(mutableListOf()) { index, item -> + item.parseColorStop(defaultOffset = index.toFloat() / items.lastIndex.coerceAtLeast(1)) + } + + if (colorStops.isEmpty()) { + val startColor = attributeOrNull(ANDROID_NS, "startColor")?.let(::parseColorValue) + val centerColor = attributeOrNull(ANDROID_NS, "centerColor")?.let(::parseColorValue) + val endColor = attributeOrNull(ANDROID_NS, "endColor")?.let(::parseColorValue) + + if (startColor != null) { + colorStops.add(0f to Color(startColor)) + } + if (centerColor != null) { + colorStops.add(0.5f to Color(centerColor)) + } + if (endColor != null) { + colorStops.add(1f to Color(endColor)) + } + } + + return colorStops.toTypedArray() +} + +private fun Element.parseColorStop(defaultOffset: Float): Pair? { + val offset = attributeOrNull(ANDROID_NS, "offset")?.toFloat() ?: defaultOffset + val color = attributeOrNull(ANDROID_NS, "color")?.let(::parseColorValue) ?: return null + return offset to Color(color) +} + +/*** + * Accessing by namespace does not appear to be working with https://github.com/pdvrieze/xmlutil v0.86.0 + * note: on native ":" had to be prepended to name to load attributes 🤷‍, js works fine without prepending ":" + * todo: figure out how to handle namespaces + */ +internal expect fun Element.attributeOrNull(@Suppress("UNUSED_PARAMETER") namespace: String, name: String): String? + +/** + * Attribute of an element can be represented as a separate child: + * + * + * + * + * + * + * + * instead of: + * + * + */ +private fun Element.apptAttr( + namespace: String, + name: String +): Element? { + val prefix = lookupPrefix(namespace) ?: return null + return childrenSequence + .filterIsElement() + .find { + it.namespaceURI == AAPT_NS && it.localName == "attr" && + it.getAttribute("name") == "$prefix:$name" + } +} + +private val Element.childrenSequence + get() = sequence { + for (childNode in childNodes.iterator()) { + yield(childNode) + } + } \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/filterIsElement.kt b/kamel-image/src/nonJvmMain/kotlin/filterIsElement.kt new file mode 100644 index 00000000..4e59eeca --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/filterIsElement.kt @@ -0,0 +1,4 @@ +import nl.adaptivity.xmlutil.dom.Element +import nl.adaptivity.xmlutil.dom.Node + +internal expect fun Sequence.filterIsElement(): Sequence diff --git a/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/config/KamelConfig.kt b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/config/KamelConfig.kt new file mode 100644 index 00000000..f31b3c1f --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/config/KamelConfig.kt @@ -0,0 +1,9 @@ +package io.kamel.image.config + +import io.kamel.core.config.KamelConfigBuilder +import io.kamel.image.decoder.ImageVectorDecoder +import io.kamel.image.decoder.SvgDecoder + +public fun KamelConfigBuilder.imageVectorDecoder(): Unit = decoder(ImageVectorDecoder) + +public fun KamelConfigBuilder.svgDecoder(): Unit = decoder(SvgDecoder) \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/ImageBitmapDecoder.kt b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/ImageBitmapDecoder.kt new file mode 100644 index 00000000..5d2c6c6f --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/ImageBitmapDecoder.kt @@ -0,0 +1,24 @@ +package io.kamel.image.decoder + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.toComposeImageBitmap +import io.kamel.core.config.ResourceConfig +import io.kamel.core.decoder.Decoder +import io.ktor.util.* +import io.ktor.utils.io.* +import org.jetbrains.skia.Image +import kotlin.reflect.KClass + +/** + * Decodes and transfers [ByteReadChannel] to [ImageBitmap] using Skia [Image]. + */ +internal actual object ImageBitmapDecoder : Decoder { + + override val outputKClass: KClass = ImageBitmap::class + + override suspend fun decode( + channel: ByteReadChannel, + resourceConfig: ResourceConfig + ): ImageBitmap = Image.makeFromEncoded(channel.toByteArray()).toComposeImageBitmap() + +} \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/ImageVectorDecoder.kt b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/ImageVectorDecoder.kt new file mode 100644 index 00000000..b9d809b3 --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/ImageVectorDecoder.kt @@ -0,0 +1,20 @@ +package io.kamel.image.decoder + +import androidx.compose.ui.graphics.vector.ImageVector +//import androidx.compose.ui.res.loadXmlImageVector +import io.kamel.core.config.ResourceConfig +import io.kamel.core.decoder.Decoder +import io.ktor.util.* +import io.ktor.utils.io.* +import loadXmlImageVector +import kotlin.reflect.KClass + +internal object ImageVectorDecoder : Decoder { + + override val outputKClass: KClass = ImageVector::class + + override suspend fun decode(channel: ByteReadChannel, resourceConfig: ResourceConfig): ImageVector { + val xml = channel.toByteArray().decodeToString() + return loadXmlImageVector(xml, resourceConfig.density) + } +} \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/SvgDecoder.kt b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/SvgDecoder.kt new file mode 100644 index 00000000..737afcfb --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/io/kamel/image/decoder/SvgDecoder.kt @@ -0,0 +1,22 @@ +package io.kamel.image.decoder + +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.loadSvgPainter +import io.kamel.core.config.ResourceConfig +import io.kamel.core.decoder.Decoder +import io.ktor.util.* +import io.ktor.utils.io.* +import kotlin.reflect.KClass + + +internal object SvgDecoder : Decoder { + + override val outputKClass: KClass = Painter::class + + override suspend fun decode(channel: ByteReadChannel, resourceConfig: ResourceConfig): Painter { + return loadSvgPainter( + channel.toByteArray(), + resourceConfig.density + ) + } +} diff --git a/kamel-image/src/nonJvmMain/kotlin/loadSvgPainter.kt b/kamel-image/src/nonJvmMain/kotlin/loadSvgPainter.kt new file mode 100644 index 00000000..7204d8d0 --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/loadSvgPainter.kt @@ -0,0 +1,113 @@ +package androidx.compose.ui.res + +import DrawCache +import androidx.compose.runtime.Composable +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.isSpecified +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntSize +import io.ktor.util.* +import io.ktor.utils.io.* +import org.jetbrains.skia.Data +import org.jetbrains.skia.Rect +import org.jetbrains.skia.svg.* +import kotlin.math.ceil + +/** + * Synchronously load an SVG image from some [inputStream]. + * + * In contrast to [svgResource] this function isn't [Composable] + * + * @param inputStream input stream to load an SVG resource. All bytes will be read from this stream, + * but stream will not be closed after this method. + * @param density density that will be used to set the intrinsic size of the Painter. If the image + * will be drawn with the specified size, density will have no effect. + * @return the decoded SVG image associated with the resource + */ +// Note: copied from here: +// https://github.com/JetBrains/compose-multiplatform-core/blob/5c26b7b9f5619ee4f319c6caf43192851b8ee15e/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/res/DesktopSvgResources.desktop.kt#L51 +// todo: remove when available in common androidx +internal fun loadSvgPainter( + bytes: ByteArray, + density: Density +): Painter { + val data = Data.makeFromBytes(bytes) + return SVGPainter(SVGDOM(data), density) +} + +private class SVGPainter( + private val dom: SVGDOM, + private val density: Density +) : Painter() { + private val root = dom.root + + private val defaultSizePx: Size = run { + val width = root?.width?.withUnit(SVGLengthUnit.PX)?.value ?: 0f + val height = root?.height?.withUnit(SVGLengthUnit.PX)?.value ?: 0f + if (width == 0f && height == 0f) { + Size.Unspecified + } else { + Size(width, height) + } + } + + init { + if (root?.viewBox == null && defaultSizePx.isSpecified) { + root?.viewBox = Rect.makeXYWH(0f, 0f, defaultSizePx.width, defaultSizePx.height) + } + } + + override val intrinsicSize: Size + get() { + return if (defaultSizePx.isSpecified) { + defaultSizePx * density.density + } else { + Size.Unspecified + } + } + + private var previousDrawSize: Size = Size.Unspecified + private var alpha: Float = 1.0f + private var colorFilter: ColorFilter? = null + + // with caching into bitmap FPS is 3x-4x higher (tested with idea-logo.svg with 30x30 icons) + private val drawCache = DrawCache() + + override fun applyAlpha(alpha: Float): Boolean { + this.alpha = alpha + return true + } + + override fun applyColorFilter(colorFilter: ColorFilter?): Boolean { + this.colorFilter = colorFilter + return true + } + + override fun DrawScope.onDraw() { + if (previousDrawSize != size) { + drawCache.drawCachedImage( + IntSize(ceil(size.width).toInt(), ceil(size.height).toInt()), + density = this, + layoutDirection, + ) { + drawSvg(size) + } + } + + drawCache.drawInto(this, alpha, colorFilter) + } + + private fun DrawScope.drawSvg(size: Size) { + drawIntoCanvas { canvas -> + root?.width = SVGLength(size.width, SVGLengthUnit.PX) + root?.height = SVGLength(size.height, SVGLengthUnit.PX) + root?.preserveAspectRatio = SVGPreserveAspectRatio(SVGPreserveAspectRatioAlign.NONE) + dom.render(canvas.nativeCanvas) + } + } +} \ No newline at end of file diff --git a/kamel-image/src/nonJvmMain/kotlin/loadXmlImageVector.kt b/kamel-image/src/nonJvmMain/kotlin/loadXmlImageVector.kt new file mode 100644 index 00000000..41a53bd9 --- /dev/null +++ b/kamel-image/src/nonJvmMain/kotlin/loadXmlImageVector.kt @@ -0,0 +1,27 @@ +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.Density +import nl.adaptivity.xmlutil.dom.Element +import nl.adaptivity.xmlutil.serialization.ElementSerializer +import nl.adaptivity.xmlutil.serialization.XML + +/** + * Synchronously load an xml vector image from some [xmlString]. + * + * XML Vector Image came from Android world. See: + * https://developer.android.com/guide/topics/graphics/vector-drawable-resources + * + * On desktop it is fully implemented except there is no resource linking + * (for example, we can't reference to color defined in another file) + * + * @param xmlString input xml vector image string. + * @param density density that will be used to set the default size of the ImageVector. If the image + * will be drawn with the specified size, density will have no effect. + * @return the decoded vector image associated with the image + */ +internal fun loadXmlImageVector( + xmlString: String, + density: Density +): ImageVector { + val element: Element = XML.decodeFromString(ElementSerializer, xmlString) + return element.parseVectorRoot(density) +} \ No newline at end of file diff --git a/kamel-samples/build.gradle.kts b/kamel-samples/build.gradle.kts index 37b43c98..19ee563c 100644 --- a/kamel-samples/build.gradle.kts +++ b/kamel-samples/build.gradle.kts @@ -1,9 +1,19 @@ +import org.jetbrains.compose.desktop.application.tasks.AbstractNativeMacApplicationPackageAppDirTask import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode +import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractExecutable +import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink +import org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutImpl +import java.io.File +import java.io.FileFilter +import org.jetbrains.compose.experimental.dsl.IOSDevices as IOSDevices1 +import org.jetbrains.kotlin.konan.file.File as KonanFile plugins { multiplatform compose `android-application` + mokoResources } android { @@ -18,8 +28,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } packagingOptions { @@ -27,42 +37,49 @@ android { excludes += setOf("META-INF/AL2.0", "META-INF/LGPL2.1") } } - - sourceSets { - named("main") { - manifest.srcFile("src/androidMain/AndroidManifest.xml") - res.srcDirs("src/androidMain/res", "src/commonMain/resources") - } - } - - configurations { - create("androidTestApi") - create("androidTestDebugApi") - create("androidTestReleaseApi") - create("testApi") - create("testDebugApi") - create("testReleaseApi") - named("implementation") { - exclude(group = "androidx.compose.animation") - exclude(group = "androidx.compose.foundation") - exclude(group = "androidx.compose.material") - exclude(group = "androidx.compose.runtime") - exclude(group = "androidx.compose.ui") - } - } } kotlin { explicitApi = ExplicitApiMode.Warning + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of("11")) + } + android() - jvm("desktop") { - compilations.all { - kotlinOptions { - jvmTarget = "11" + jvm("desktop") + js(IR) { + browser() + binaries.executable() + } + for (target in Targets.macosTargets) { + targets.add( + (presets.getByName(target) + .createTarget(target) as org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget).apply { + binaries.executable { + freeCompilerArgs += listOf( + "-linker-option", "-framework", "-linker-option", "Metal" + ) + } } - } + ) + } + for (target in Targets.iosTargets) { + targets.add( + (presets.getByName(target) + .createTarget(target.replace("ios", "uikit")) + as org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget).apply { + binaries.executable { + entryPoint = "main" + freeCompilerArgs += listOf( + "-linker-option", "-framework", "-linker-option", "Metal", + "-linker-option", "-framework", "-linker-option", "CoreText", + "-linker-option", "-framework", "-linker-option", "CoreGraphics" + ) + } + } + ) } sourceSets { @@ -71,15 +88,15 @@ kotlin { dependencies { implementation(project(":kamel-image")) implementation(project(":kamel-tests")) + implementation(compose.foundation) implementation(compose.material) - implementation(compose.animation) } } val androidMain by getting { + dependsOn(commonMain) dependencies { implementation(Dependencies.Android.Appcompat) - implementation(Dependencies.Android.Core) implementation(Dependencies.Android.ActivityCompose) implementation(Dependencies.Android.Material) implementation(Dependencies.Ktor.Android) @@ -87,34 +104,177 @@ kotlin { } val desktopMain by getting { + dependsOn(commonMain) dependencies { implementation(compose.desktop.currentOs) implementation(Dependencies.Ktor.CIO) } } - all { - languageSettings.apply { - optIn("kotlin.Experimental") + val darwinMain by creating { + dependsOn(commonMain) + } + + val macosMain by creating { + dependsOn(darwinMain) + } + + Targets.macosTargets.forEach { target -> + getByName("${target}Main") { + dependsOn(macosMain) } } - targets.all { - compilations.all { - kotlinOptions { - freeCompilerArgs = - listOf("-Xopt-in=kotlin.RequiresOptIn") - } + val uikitMain by creating { + dependsOn(darwinMain) + } + + Targets.iosTargets.map { target -> + target.replace("ios", "uikit") + }.forEach { target -> + getByName("${target}Main") { + dependsOn(uikitMain) + } + } + + all { + languageSettings.apply { + optIn("kotlin.Experimental") } } } } + +multiplatformResources { + multiplatformResourcesPackage = "io.kamel.samples" +} + + compose { desktop { application { mainClass = "io.kamel.samples.DesktopSampleKt" } } -} \ No newline at end of file +} + +compose.experimental { + web.application {} + uikit.application { + bundleIdPrefix = "io.kamel.samples" + projectName = "kamel samples" + deployConfigurations { + simulator("IPhone13") { + //Usage: ./gradlew iosDeployIPhone8Debug + device = IOSDevices1.IPHONE_13 + } + simulator("IPad") { + //Usage: ./gradlew iosDeployIPadDebug + device = IOSDevices1.IPAD_PRO_11_INCH_3rd_Gen + } + connectedDevice("Device") { + //First need specify your teamId here, or in local.properties (compose.ios.teamId=***) + //teamId="***" + //Usage: ./gradlew iosDeployDeviceRelease + } + } + } +} + + +compose.desktop.nativeApplication { + targets(kotlin.targets.getByName("macosArm64")) + distributions { + targetFormats(org.jetbrains.compose.desktop.application.dsl.TargetFormat.Dmg) + packageName = "Native-Sample" + packageVersion = "1.0.0" + } +} + +// TODO: remove when https://youtrack.jetbrains.com/issue/KT-50778 fixed +project.tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile::class.java).configureEach { + kotlinOptions.freeCompilerArgs += listOf( + "-Xir-dce-runtime-diagnostic=log" + ) +} + +// todo: remove after https://github.com/icerockdev/moko-resources/issues/392 resolved +// copy resources from kamel-tests into the proper directory for kamel-samples so they are packaged for +// the web app +tasks.register("jsCopyResourcesFromKamelTests") { + from("../kamel-tests/build/generated/moko/jsMain/iokameltests/res") + into("build/generated/moko/jsMain/iokamelsamples/res") + dependsOn(":kamel-tests:generateMRjsMain") +} +tasks.getByName("jsProcessResources").dependsOn("jsCopyResourcesFromKamelTests") + +tasks.register("desktopCopyResourcesFromKamelTests") { + from("../kamel-tests/build/generated/moko/jvmMain/iokameltests/res") + into("build/generated/moko/desktopMain/iokamelsamples/res") + dependsOn(":kamel-tests:generateMRjvmMain") +} +tasks.getByName("desktopProcessResources").dependsOn("desktopCopyResourcesFromKamelTests") + +// todo: Remove when resolved: https://github.com/icerockdev/moko-resources/issues/372 +tasks.withType() + .matching { linkTask -> linkTask.binary is AbstractExecutable } + .configureEach { + val task: KotlinNativeLink = this + + doLast { + val binary: NativeBinary = task.binary + val outputDir: File = task.outputFile.get().parentFile + task.libraries + .filter { library -> library.extension == "klib" } + .filter(File::exists) + .forEach { inputFile -> + val klibKonan = KonanFile(inputFile.path) + val klib = KotlinLibraryLayoutImpl( + klib = klibKonan, + component = "default" + ) + val layout = klib.extractingToTemp + + // extracting bundles + layout + .resourcesDir + .absolutePath + .let(::File) + .listFiles(FileFilter { it.extension == "bundle" }) + // copying bundles to app + ?.forEach { bundleFile -> + logger.info("${bundleFile.absolutePath} copying to $outputDir") + bundleFile.copyRecursively( + target = File(outputDir, bundleFile.name), + overwrite = true + ) + } + } + } + } + +tasks.withType { + val task: AbstractNativeMacApplicationPackageAppDirTask = this + + doLast { + val execFile: File = task.executable.get().asFile + val execDir: File = execFile.parentFile + val destDir: File = task.destinationDir.asFile.get() + val bundleID: String = task.bundleID.get() + + val outputDir = File(destDir, "$bundleID.app/Contents/Resources") + outputDir.mkdirs() + + execDir.listFiles().orEmpty() + .filter { it.extension == "bundle" } + .forEach { bundleFile -> + logger.info("${bundleFile.absolutePath} copying to $outputDir") + bundleFile.copyRecursively( + target = File(outputDir, bundleFile.name), + overwrite = true + ) + } + } +} diff --git a/kamel-samples/src/androidMain/kotlin/io/kamel/samples/AndroidSample.kt b/kamel-samples/src/androidMain/kotlin/io/kamel/samples/AndroidSample.kt index 092aa949..3f0e4d64 100644 --- a/kamel-samples/src/androidMain/kotlin/io/kamel/samples/AndroidSample.kt +++ b/kamel-samples/src/androidMain/kotlin/io/kamel/samples/AndroidSample.kt @@ -3,6 +3,12 @@ package io.kamel.samples import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity +import androidx.compose.runtime.remember +import io.kamel.core.config.KamelConfig +import io.kamel.core.config.takeFrom +import io.kamel.image.config.Default +import io.kamel.image.config.imageBitmapDecoder +import io.kamel.image.config.resourcesFetcher public actual val cellsCount: Int = 2 @@ -11,7 +17,16 @@ class AndroidSample : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - Gallery() + val kamelConfig = remember { + KamelConfig { + takeFrom(KamelConfig.Default) + resourcesFetcher(this@AndroidSample) +// imageVectorDecoder() +// svgDecsoder() + imageBitmapDecoder() + } + } + launcher(kamelConfig, applicationContext) } } diff --git a/kamel-samples/src/androidMain/kotlin/io/kamel/samples/ResourcesSample.kt b/kamel-samples/src/androidMain/kotlin/io/kamel/samples/ResourcesSample.kt deleted file mode 100644 index e694ccc0..00000000 --- a/kamel-samples/src/androidMain/kotlin/io/kamel/samples/ResourcesSample.kt +++ /dev/null @@ -1,48 +0,0 @@ -package io.kamel.samples - -import android.os.Bundle -import androidx.activity.compose.setContent -import androidx.appcompat.app.AppCompatActivity -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import io.kamel.core.config.KamelConfig -import io.kamel.core.config.takeFrom -import io.kamel.image.KamelImage -import io.kamel.image.config.Default -import io.kamel.image.config.LocalKamelConfig -import io.kamel.image.config.resourcesFetcher -import io.kamel.image.config.resourcesIdMapper -import io.kamel.image.lazyImageResource -import io.kamel.image.lazyPainterResource - -class ResourcesSample : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - - val context = LocalContext.current - - val androidConfig = KamelConfig { - takeFrom(KamelConfig.Default) - resourcesFetcher(context) - resourcesIdMapper(context) - } - - CompositionLocalProvider(LocalKamelConfig provides androidConfig) { - - val imageResource = lazyPainterResource(R.raw.compose) - - KamelImage( - resource = imageResource, - contentDescription = "Compose", - modifier = Modifier.fillMaxSize(), - ) - - } - - } - } -} \ No newline at end of file diff --git a/kamel-samples/src/androidMain/kotlin/io/kamel/samples/getFile.kt b/kamel-samples/src/androidMain/kotlin/io/kamel/samples/getFile.kt new file mode 100644 index 00000000..ebb6bb49 --- /dev/null +++ b/kamel-samples/src/androidMain/kotlin/io/kamel/samples/getFile.kt @@ -0,0 +1,29 @@ +package io.kamel.samples + +import android.content.Context +import android.content.res.Resources +import android.util.Log +import android.util.TypedValue +import dev.icerock.moko.resources.FileResource +import io.kamel.core.utils.File +import java.io.FileOutputStream +import java.io.InputStream + + +public actual suspend fun getFile(fileResource: FileResource, context: Any?): File { + val resources: Resources = (context as Context).resources + val value = TypedValue() + resources.getValue(fileResource.rawResId, value, true) + val name = value.string.toString() + val file = java.io.File.createTempFile("temp", ".${name.substringAfterLast(".")}") + val ins: InputStream = resources.openRawResource(fileResource.rawResId) + FileOutputStream(file).use { os -> + val buffer = ByteArray(4096) + var length: Int + while (ins.read(buffer).also { length = it } > 0) { + os.write(buffer, 0, length) + } + os.flush() + } + return file +} \ No newline at end of file diff --git a/kamel-samples/src/commonMain/kotlin/io/kamel/samples/FileSample.kt b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/FileSample.kt new file mode 100644 index 00000000..c82e2fc8 --- /dev/null +++ b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/FileSample.kt @@ -0,0 +1,38 @@ +package io.kamel.samples + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import dev.icerock.moko.resources.FileResource +import io.kamel.core.config.KamelConfig +import io.kamel.core.utils.File +import io.kamel.image.KamelImage +import io.kamel.image.config.LocalKamelConfig +import io.kamel.image.lazyPainterResource +import kotlinx.coroutines.launch + + +@Composable +internal fun FileSample(fileResource: FileResource, kamelConfig: KamelConfig, context: Any? = null) { + + val scope = rememberCoroutineScope() + var file: File? by remember { mutableStateOf(null) } + + scope.launch { + file = getFile(fileResource, context) + } + + + CompositionLocalProvider(LocalKamelConfig provides kamelConfig) { + Column { + file?.let { file -> + val painterResource = lazyPainterResource(file) + KamelImage(painterResource, + contentDescription = "Compose", + modifier = Modifier.fillMaxSize(), + onFailure = { throw it }) + } + } + } +} diff --git a/kamel-samples/src/commonMain/kotlin/io/kamel/samples/Gallery.kt b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/Gallery.kt index 8f524d72..5e61ba28 100644 --- a/kamel-samples/src/commonMain/kotlin/io/kamel/samples/Gallery.kt +++ b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/Gallery.kt @@ -50,7 +50,7 @@ public fun Gallery() { contentDescription = null, modifier = Modifier .aspectRatio(1F) - .padding(16.dp) + .padding(8.dp) .shadow(elevation = 8.dp, RoundedCornerShape(16.dp)) .background(Color.White, RoundedCornerShape(16.dp)) .clip(RoundedCornerShape(16.dp)), diff --git a/kamel-samples/src/commonMain/kotlin/io/kamel/samples/getFile.kt b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/getFile.kt new file mode 100644 index 00000000..63930b15 --- /dev/null +++ b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/getFile.kt @@ -0,0 +1,7 @@ +package io.kamel.samples + +import dev.icerock.moko.resources.AssetResource +import dev.icerock.moko.resources.FileResource +import io.kamel.core.utils.File + +public expect suspend fun getFile(fileResource: FileResource, context: Any? = null): File \ No newline at end of file diff --git a/kamel-samples/src/commonMain/kotlin/io/kamel/samples/launcher.kt b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/launcher.kt new file mode 100644 index 00000000..06f20b97 --- /dev/null +++ b/kamel-samples/src/commonMain/kotlin/io/kamel/samples/launcher.kt @@ -0,0 +1,49 @@ +package io.kamel.samples + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import io.kamel.core.config.KamelConfig +import io.kamel.tests.MR + +@androidx.compose.runtime.Composable +public fun launcher(kamelConfig: KamelConfig, context: Any? = null) { + var sampleIndex by remember { mutableStateOf(0) } + Column { + Row { + Button({ + sampleIndex = 0 + }) { + Text("Gallery") + } + Button({ + sampleIndex = 1 + }) { + Text("Bitmap") + } + Button({ + sampleIndex = 2 + }) { + Text("Svg") + } + Button({ + sampleIndex = 3 + }) { + Text("Xml") + } + } + when (sampleIndex) { + 0 -> Gallery() + 1 -> FileSample(MR.files.Compose, kamelConfig, context) + 2 -> FileSample(MR.files.Kotlin, kamelConfig, context) + 3 -> FileSample(MR.files.ComposeXml, kamelConfig, context) + + else -> Text("Invalid Sample Index") + } + } +} \ No newline at end of file diff --git a/kamel-samples/src/darwinMain/kotlin/io/kamel/samples/darwinCellsCount.kt b/kamel-samples/src/darwinMain/kotlin/io/kamel/samples/darwinCellsCount.kt new file mode 100644 index 00000000..f2b4dfd8 --- /dev/null +++ b/kamel-samples/src/darwinMain/kotlin/io/kamel/samples/darwinCellsCount.kt @@ -0,0 +1,4 @@ +package io.kamel.samples + + +public actual val cellsCount: Int = 4 diff --git a/kamel-samples/src/darwinMain/kotlin/io/kamel/samples/getFile.kt b/kamel-samples/src/darwinMain/kotlin/io/kamel/samples/getFile.kt new file mode 100644 index 00000000..b9c210a8 --- /dev/null +++ b/kamel-samples/src/darwinMain/kotlin/io/kamel/samples/getFile.kt @@ -0,0 +1,9 @@ +package io.kamel.samples + +import dev.icerock.moko.resources.FileResource +import io.kamel.core.utils.File +import io.kamel.tests.MR + +public actual suspend fun getFile(fileResource: FileResource, context: Any?): File { + return File(fileResource.path) +} \ No newline at end of file diff --git a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/DesktopSample.kt b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/DesktopSample.kt index fcad554d..871c8b87 100644 --- a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/DesktopSample.kt +++ b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/DesktopSample.kt @@ -1,7 +1,22 @@ package io.kamel.samples +import androidx.compose.runtime.remember import androidx.compose.ui.window.singleWindowApplication +import io.kamel.core.config.KamelConfig +import io.kamel.core.config.takeFrom +import io.kamel.image.config.* public actual val cellsCount: Int = 4 -public fun main(): Unit = singleWindowApplication { Gallery() } \ No newline at end of file +public fun main(): Unit = singleWindowApplication { + val kamelConfig = remember { + KamelConfig { + takeFrom(KamelConfig.Default) + resourcesFetcher() + imageVectorDecoder() + svgDecoder() + imageBitmapDecoder() + } + } + launcher(kamelConfig) +} \ No newline at end of file diff --git a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/FileSample.kt b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/FileSample.kt deleted file mode 100644 index 50f7f259..00000000 --- a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/FileSample.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.kamel.samples - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.Modifier -import androidx.compose.ui.window.singleWindowApplication -import io.kamel.core.config.KamelConfig -import io.kamel.core.config.takeFrom -import io.kamel.image.KamelImage -import io.kamel.image.config.Default -import io.kamel.image.config.LocalKamelConfig -import io.kamel.image.config.imageVectorDecoder -import io.kamel.image.config.resourcesFetcher -import io.kamel.image.lazyPainterResource -import java.io.File - -public fun main(): Unit = singleWindowApplication { - val kamelConfig = KamelConfig { - takeFrom(KamelConfig.Default) - resourcesFetcher() - imageVectorDecoder() - } - - CompositionLocalProvider(LocalKamelConfig provides kamelConfig) { - val painterResource = - lazyPainterResource(File("kamel-tests/src/commonMain/resources/Compose.png")) - - KamelImage( - painterResource, - contentDescription = "Compose", - modifier = Modifier.fillMaxSize(), - onFailure = { throw it } - ) - } -} \ No newline at end of file diff --git a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/ResourcesSample.kt b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/ResourcesSample.kt index 43c2b782..5b020d63 100644 --- a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/ResourcesSample.kt +++ b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/ResourcesSample.kt @@ -19,7 +19,7 @@ public fun main(): Unit = singleWindowApplication { } CompositionLocalProvider(LocalKamelConfig provides kamelConfig) { - val painterResource = lazyPainterResource("Compose.png") + val painterResource = lazyPainterResource("MR/files/Compose.png") KamelImage( painterResource, diff --git a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/SvgSample.kt b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/SvgSample.kt index e527bdf5..0b5db5f8 100644 --- a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/SvgSample.kt +++ b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/SvgSample.kt @@ -21,7 +21,7 @@ public fun main(): Unit = singleWindowApplication { } CompositionLocalProvider(LocalKamelConfig provides kamelConfig) { - val painterResource = lazyPainterResource("Kotlin.svg") + val painterResource = lazyPainterResource("MR/files/Kotlin.svg") KamelImage( painterResource, diff --git a/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/getFile.kt b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/getFile.kt new file mode 100644 index 00000000..8ea6d9ea --- /dev/null +++ b/kamel-samples/src/desktopMain/kotlin/io/kamel/samples/getFile.kt @@ -0,0 +1,20 @@ +package io.kamel.samples + +import dev.icerock.moko.resources.FileResource +import io.kamel.core.utils.File +import java.io.FileOutputStream + + +public actual suspend fun getFile(fileResource: FileResource, context: Any?): File { + val file = java.io.File.createTempFile("temp", ".${fileResource.filePath.substringAfterLast(".")}") + val ins = Thread.currentThread().contextClassLoader.getResource(fileResource.filePath).openStream() + FileOutputStream(file).use { os -> + val buffer = ByteArray(4096) + var length: Int + while (ins.read(buffer).also { length = it } > 0) { + os.write(buffer, 0, length) + } + os.flush() + } + return file +} \ No newline at end of file diff --git a/kamel-samples/src/jsMain/kotlin/io/kamel/samples/cellsCount.kt b/kamel-samples/src/jsMain/kotlin/io/kamel/samples/cellsCount.kt new file mode 100644 index 00000000..f2b4dfd8 --- /dev/null +++ b/kamel-samples/src/jsMain/kotlin/io/kamel/samples/cellsCount.kt @@ -0,0 +1,4 @@ +package io.kamel.samples + + +public actual val cellsCount: Int = 4 diff --git a/kamel-samples/src/jsMain/kotlin/io/kamel/samples/getFile.kt b/kamel-samples/src/jsMain/kotlin/io/kamel/samples/getFile.kt new file mode 100644 index 00000000..25d0c11a --- /dev/null +++ b/kamel-samples/src/jsMain/kotlin/io/kamel/samples/getFile.kt @@ -0,0 +1,14 @@ +package io.kamel.samples + +import dev.icerock.moko.resources.FileResource +import io.kamel.core.utils.File +import kotlinx.browser.window +import kotlinx.coroutines.await + +public actual suspend fun getFile(fileResource: FileResource, context: Any?): File { + val blob = window.fetch(fileResource.fileUrl).await().blob().await() + return File(org.w3c.files.File( + arrayOf(blob), + fileResource.fileUrl + )) +} \ No newline at end of file diff --git a/kamel-samples/src/jsMain/kotlin/main.js.kt b/kamel-samples/src/jsMain/kotlin/main.js.kt new file mode 100644 index 00000000..2d79a87e --- /dev/null +++ b/kamel-samples/src/jsMain/kotlin/main.js.kt @@ -0,0 +1,20 @@ +import androidx.compose.ui.window.Window +import io.kamel.core.config.KamelConfig +import io.kamel.core.config.takeFrom +import io.kamel.image.config.* +import io.kamel.samples.launcher +import org.jetbrains.skiko.wasm.onWasmReady + +public fun main() { + val kamelConfig = KamelConfig { + takeFrom(KamelConfig.Default) + imageVectorDecoder() + svgDecoder() + imageBitmapDecoder() + } + onWasmReady { + Window("Sample") { + launcher(kamelConfig) + } + } +} \ No newline at end of file diff --git a/kamel-samples/src/jsMain/resources/index.html b/kamel-samples/src/jsMain/resources/index.html new file mode 100644 index 00000000..fd014742 --- /dev/null +++ b/kamel-samples/src/jsMain/resources/index.html @@ -0,0 +1,15 @@ + + + + + Kamel Samples + + + + +
+ +
+ + + \ No newline at end of file diff --git a/kamel-samples/src/jsMain/resources/styles.css b/kamel-samples/src/jsMain/resources/styles.css new file mode 100644 index 00000000..e5b3293a --- /dev/null +++ b/kamel-samples/src/jsMain/resources/styles.css @@ -0,0 +1,8 @@ +#root { + width: 100%; + height: 100vh; +} + +#root > .compose-web-column > div { + position: relative; +} \ No newline at end of file diff --git a/kamel-samples/src/macosMain/kotlin/main.macos.kt b/kamel-samples/src/macosMain/kotlin/main.macos.kt new file mode 100644 index 00000000..bc6db61e --- /dev/null +++ b/kamel-samples/src/macosMain/kotlin/main.macos.kt @@ -0,0 +1,21 @@ +import androidx.compose.ui.window.Window +import io.kamel.core.config.KamelConfig +import io.kamel.core.config.takeFrom +import io.kamel.image.config.* +import io.kamel.samples.launcher +import platform.AppKit.NSApp +import platform.AppKit.NSApplication + +public fun main() { + NSApplication.sharedApplication() + val kamelConfig = KamelConfig { + takeFrom(KamelConfig.Default) + imageVectorDecoder() + svgDecoder() + imageBitmapDecoder() + } + Window("Sample") { + launcher(kamelConfig) + } + NSApp?.run() +} \ No newline at end of file diff --git a/kamel-samples/src/uikitMain/kotlin/main.uikit.kt b/kamel-samples/src/uikitMain/kotlin/main.uikit.kt new file mode 100644 index 00000000..8fdc59f9 --- /dev/null +++ b/kamel-samples/src/uikitMain/kotlin/main.uikit.kt @@ -0,0 +1,59 @@ +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.ComposeUIViewController +import io.kamel.core.config.KamelConfig +import io.kamel.core.config.takeFrom +import io.kamel.image.config.Default +import io.kamel.image.config.imageBitmapDecoder +import io.kamel.image.config.imageVectorDecoder +import io.kamel.image.config.svgDecoder +import io.kamel.samples.launcher +import kotlinx.cinterop.autoreleasepool +import kotlinx.cinterop.cstr +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toCValues +import platform.Foundation.NSStringFromClass +import platform.UIKit.* + +public fun main() { + val args = emptyArray() + memScoped { + val argc = args.size + 1 + val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues() + autoreleasepool { + UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate)) + } + } +} + +internal class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol { + internal companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta + + @OverrideInit + internal constructor() : super() + + private var _window: UIWindow? = null + override fun window(): UIWindow? = _window + override fun setWindow(window: UIWindow?) { + _window = window + } + + override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { + window = UIWindow(frame = UIScreen.mainScreen.bounds) + val kamelConfig = KamelConfig { + takeFrom(KamelConfig.Default) + imageVectorDecoder() + svgDecoder() + imageBitmapDecoder() + } + window!!.rootViewController = ComposeUIViewController { + Column(Modifier.padding(top = 30.dp)) { + launcher(kamelConfig) + } + } + window!!.makeKeyAndVisible() + return true + } +} diff --git a/kamel-tests/build.gradle.kts b/kamel-tests/build.gradle.kts index 2e4ec16d..717eced6 100644 --- a/kamel-tests/build.gradle.kts +++ b/kamel-tests/build.gradle.kts @@ -1,23 +1,74 @@ plugins { + `android-library` multiplatform + mokoResources } kotlin { jvm() + android() + js(IR) { + browser() + } + for (target in Targets.nativeTargets) { + targets.add(presets.getByName(target).createTarget(target)) + } sourceSets { val commonMain by getting { dependencies { implementation(Dependencies.Testing.Ktor) - implementation(Dependencies.Testing.Compose) - implementation(Dependencies.Testing.Coroutines) + implementation(Dependencies.Coroutines.Core) + api(Dependencies.MokoResources.Core) } } val commonTest by getting { dependencies { - implementation(kotlin("test-common")) - implementation(kotlin("test-annotations-common")) + implementation(kotlin("test")) + api(Dependencies.MokoResources.Test) } } + + val darwinMain by creating { + dependsOn(commonMain) + } + + val darwinTest by creating { + dependsOn(commonTest) + } + + Targets.darwinTargets.forEach { target -> + getByName("${target}Main") { + dependsOn(darwinMain) + } + getByName("${target}Test") { + dependsOn(darwinTest) + } + } + } +} + +android { + compileSdk = 33 + + defaultConfig { + minSdk = 16 } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + defaultConfig { + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + //https://github.com/icerockdev/moko-resources/issues/403 + sourceSets["main"].res.srcDir(File(buildDir, "generated/moko/androidMain/res")) +} + + +multiplatformResources { + multiplatformResourcesPackage = "io.kamel.tests" } \ No newline at end of file diff --git a/kamel-tests/src/androidMain/AndroidManifest.xml b/kamel-tests/src/androidMain/AndroidManifest.xml new file mode 100644 index 00000000..17e5f52a --- /dev/null +++ b/kamel-tests/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/kamel-tests/src/androidMain/kotlin/io/kamel/tests/AndroidTestUtils.kt b/kamel-tests/src/androidMain/kotlin/io/kamel/tests/AndroidTestUtils.kt new file mode 100644 index 00000000..f89696e3 --- /dev/null +++ b/kamel-tests/src/androidMain/kotlin/io/kamel/tests/AndroidTestUtils.kt @@ -0,0 +1,17 @@ +package io.kamel.tests + +import io.ktor.utils.io.* +import io.ktor.utils.io.core.* + + +actual suspend fun resourceImage(): ByteReadChannel { + TODO() +// val bytes = MR.assets.Compose.readText().encodeToByteArray() +// return ByteReadChannel(bytes) +} + +actual suspend fun svgImage(): ByteReadChannel { + TODO() +// val bytes = MR.files.Kotlin.readText().encodeToByteArray() +// return ByteReadChannel(bytes) +} diff --git a/kamel-tests/src/commonMain/kotlin/io/kamel/tests/HttpMockEngine.kt b/kamel-tests/src/commonMain/kotlin/io/kamel/tests/HttpMockEngine.kt index 02cc2925..eb6c65f6 100644 --- a/kamel-tests/src/commonMain/kotlin/io/kamel/tests/HttpMockEngine.kt +++ b/kamel-tests/src/commonMain/kotlin/io/kamel/tests/HttpMockEngine.kt @@ -7,13 +7,13 @@ import io.ktor.utils.io.* val HttpMockEngine = MockEngine { request -> when (request.url.encodedPath) { "/emptyImage.jpg" -> respond(ByteReadChannel.Empty) - "/image.jpg" -> respond(resourceImage) - "/image.svg" -> respond(svgImage) + "/image.jpg" -> respond(resourceImage()) + "/image.svg" -> respond(svgImage()) else -> respondError(HttpStatusCode.NotFound) } } const val TestStringUrl = "https://www.example.com" -expect val resourceImage: ByteReadChannel -expect val svgImage: ByteReadChannel \ No newline at end of file +expect suspend fun resourceImage(): ByteReadChannel +expect suspend fun svgImage(): ByteReadChannel \ No newline at end of file diff --git a/kamel-tests/src/commonMain/resources/Compose.png b/kamel-tests/src/commonMain/resources/MR/files/Compose.png similarity index 100% rename from kamel-tests/src/commonMain/resources/Compose.png rename to kamel-tests/src/commonMain/resources/MR/files/Compose.png diff --git a/kamel-tests/src/commonMain/resources/Compose.xml b/kamel-tests/src/commonMain/resources/MR/files/ComposeXml.xml similarity index 100% rename from kamel-tests/src/commonMain/resources/Compose.xml rename to kamel-tests/src/commonMain/resources/MR/files/ComposeXml.xml diff --git a/kamel-tests/src/commonMain/resources/Kotlin.svg b/kamel-tests/src/commonMain/resources/MR/files/Kotlin.svg similarity index 100% rename from kamel-tests/src/commonMain/resources/Kotlin.svg rename to kamel-tests/src/commonMain/resources/MR/files/Kotlin.svg diff --git a/kamel-tests/src/darwinMain/kotlin/io/kamel/tests/JvmTestUtils.kt b/kamel-tests/src/darwinMain/kotlin/io/kamel/tests/JvmTestUtils.kt new file mode 100644 index 00000000..76f78948 --- /dev/null +++ b/kamel-tests/src/darwinMain/kotlin/io/kamel/tests/JvmTestUtils.kt @@ -0,0 +1,15 @@ +package io.kamel.tests + +import io.ktor.utils.io.* +import io.ktor.utils.io.core.* + + +actual suspend fun resourceImage(): ByteReadChannel { + val bytes = MR.files.Compose.readText().encodeToByteArray() + return ByteReadChannel(bytes) +} + +actual suspend fun svgImage(): ByteReadChannel { + val bytes = MR.files.Kotlin.readText().encodeToByteArray() + return ByteReadChannel(bytes) +} diff --git a/kamel-tests/src/jsMain/kotlin/io/kamel/tests/JsTestUtils.kt b/kamel-tests/src/jsMain/kotlin/io/kamel/tests/JsTestUtils.kt new file mode 100644 index 00000000..31968b98 --- /dev/null +++ b/kamel-tests/src/jsMain/kotlin/io/kamel/tests/JsTestUtils.kt @@ -0,0 +1,13 @@ +package io.kamel.tests + +import io.ktor.utils.io.* + +actual suspend fun resourceImage(): ByteReadChannel { + val bytes = MR.files.Compose.getText().encodeToByteArray() + return ByteReadChannel(bytes) +} + +actual suspend fun svgImage(): ByteReadChannel { + val bytes = MR.files.Kotlin.getText().encodeToByteArray() + return ByteReadChannel(bytes) +} diff --git a/kamel-tests/src/jvmMain/kotlin/io/kamel/tests/JvmTestUtils.kt b/kamel-tests/src/jvmMain/kotlin/io/kamel/tests/JvmTestUtils.kt index f510c80f..0be87582 100644 --- a/kamel-tests/src/jvmMain/kotlin/io/kamel/tests/JvmTestUtils.kt +++ b/kamel-tests/src/jvmMain/kotlin/io/kamel/tests/JvmTestUtils.kt @@ -3,16 +3,12 @@ package io.kamel.tests import io.ktor.utils.io.* -actual val resourceImage: ByteReadChannel - get() { - val url = Thread.currentThread().contextClassLoader.getResource("Compose.png")!! - val bytes = url.readBytes() - return ByteReadChannel(bytes) - } - -actual val svgImage: ByteReadChannel - get() { - val url = Thread.currentThread().contextClassLoader.getResource("Kotlin.svg")!! - val bytes = url.readBytes() - return ByteReadChannel(bytes) - } +actual suspend fun resourceImage(): ByteReadChannel { + val bytes = MR.files.Compose.readText().encodeToByteArray() + return ByteReadChannel(bytes) +} + +actual suspend fun svgImage(): ByteReadChannel { + val bytes = MR.files.Kotlin.readText().encodeToByteArray() + return ByteReadChannel(bytes) +} diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock new file mode 100644 index 00000000..10befde4 --- /dev/null +++ b/kotlin-js-store/yarn.lock @@ -0,0 +1,3265 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.10.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + 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" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + +"@messageformat/core@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@messageformat/core/-/core-3.0.0.tgz#8785c283218a11ced7f1474f547824bbce583f21" + integrity sha512-mzMCyADGweNmnMwV/xjKxtXtkXJNVcK5ATOHx4Q0GVr2Z3++in1VfrB/y6jM43nleK27tFO0Y/9pds5vxWqDvQ== + dependencies: + "@messageformat/date-skeleton" "^1.0.0" + "@messageformat/number-skeleton" "^1.0.0" + "@messageformat/parser" "^5.0.0" + "@messageformat/runtime" "^3.0.0" + make-plural "^6.2.1" + safe-identifier "^0.4.1" + +"@messageformat/date-skeleton@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz#980b8babe21a11433b6e1e8f6dc8c4cae4f5f56b" + integrity sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg== + +"@messageformat/number-skeleton@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@messageformat/number-skeleton/-/number-skeleton-1.1.0.tgz#eb636738da8abbd35ccbeb84f7d84d63302aeb61" + integrity sha512-F0Io+GOSvFFxvp9Ze3L5kAoZ2NnOAT0Mr/jpGNd3fqo8A0t4NxNIAcCdggtl2B/gN2ErkIKSBVPrF7xcW1IGvA== + +"@messageformat/parser@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@messageformat/parser/-/parser-5.0.0.tgz#5737e69d7d4a469998b527710f1891174fc1b262" + integrity sha512-WiDKhi8F0zQaFU8cXgqq69eYFarCnTVxKcvhAONufKf0oUxbqLMW6JX6rV4Hqh+BEQWGyKKKHY4g1XA6bCLylA== + dependencies: + moo "^0.5.1" + +"@messageformat/runtime@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@messageformat/runtime/-/runtime-3.0.1.tgz#94d1f6c43265c28ef7aed98ecfcc0968c6c849ac" + integrity sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg== + dependencies: + make-plural "^7.0.0" + +"@rollup/plugin-commonjs@^21.0.1": + version "21.1.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz#45576d7b47609af2db87f55a6d4b46e44fc3a553" + integrity sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA== + dependencies: + "@rollup/pluginutils" "^3.1.0" + commondir "^1.0.1" + estree-walker "^2.0.1" + glob "^7.1.6" + is-reference "^1.2.1" + magic-string "^0.25.7" + resolve "^1.17.0" + +"@rollup/plugin-node-resolve@^13.1.3": + version "13.3.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c" + integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw== + 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" + +"@rollup/plugin-typescript@^8.3.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz#7ea11599a15b0a30fa7ea69ce3b791d41b862515" + integrity sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ== + dependencies: + "@rollup/pluginutils" "^3.1.0" + resolve "^1.17.0" + +"@rollup/pluginutils@^3.0.9", "@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" + integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.4.6" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.6.tgz#7976f054c1bccfcf514bff0564c0c41df5c08207" + integrity sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + +"@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": + version "4.17.30" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz#0f2f99617fa8f9696170c46152ccf7500b34ac04" + integrity sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-proxy@^1.17.8": + version "1.17.9" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" + integrity sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw== + dependencies: + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/node@*", "@types/node@>=10.0.0": + version "18.7.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.17.tgz#52438111ea98f77475470fc62d79b9eb96bb2c92" + integrity sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ== + +"@types/node@^12.12.14": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/resolve@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" + integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== + dependencies: + "@types/node" "*" + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" + integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== + dependencies: + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/ws@^8.5.1": + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== + dependencies: + "@types/node" "*" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + 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" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + 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" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + 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" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@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@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + 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" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== + +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn@^8.5.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +acorn@^8.7.1: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + 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" + +ajv@^8.0.0, ajv@^8.8.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +bcp-47@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/bcp-47/-/bcp-47-1.0.8.tgz#bf63ae4269faabe7c100deac0811121a48b6a561" + integrity sha512-Y9y1QNBBtYtv7hcmoX0tR+tUNSFZGZ6OL6vKPObq8BbOhkCoyayF6ogfLTgAli/KuAEbsYHYUNq2AQuY6IuLag== + dependencies: + is-alphabetical "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +body-parser@1.20.0, body-parser@^1.19.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" + integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== + 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" + +bonjour-service@^1.0.11: + version "1.0.14" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.14.tgz#c346f5bc84e87802d08f8d5a60b93f758e514ee7" + integrity sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ== + dependencies: + array-flatten "^2.1.2" + dns-equal "^1.0.0" + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.14.5: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== + dependencies: + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001370: + version "1.0.30001397" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001397.tgz#010d9d56e3b8abcd8df261d0a94b22426271a15f" + integrity sha512-SW9N2TbCdLf0eiNDRrrQXx2sOkaakNZbCjgNpPyMJJbiOrU5QzMIrXOVMRM1myBXTD5iTkdrtU/EguCrBocHlA== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + 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" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.3, chokidar@^3.5.1, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + 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" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.10, colorette@^2.0.14: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + 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" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-loader@6.7.3: + version "6.7.3" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.3.tgz#1e8799f3ccc5874fdd55461af51137fcc5befbcd" + integrity sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.19" + 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.8" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== + +date-format@^4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.13.tgz#87c3aab3a4f6f37582c5f5f63692d2956fa67890" + integrity sha512-bnYCwf8Emc3pTD8pXnre+wfnjGtfi5ncMDKy7+cWZXbmRAsdWkOQHrfC1yz/KiwP5thDp2kCHWYWKBX4HP1hoQ== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.3.4, debug@^4.1.0, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decode-uri-component@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.4.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" + integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +dukat@0.5.8-rc.4: + version "0.5.8-rc.4" + resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" + integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== + dependencies: + google-protobuf "3.12.2" + typescript "3.9.5" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.202: + version "1.4.248" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.248.tgz#dd2dab68277e91e8452536ee9265f484066f94ad" + integrity sha512-qShjzEYpa57NnhbW2K+g+Fl+eNoDvQ7I+2MRwWnU6Z6F0HhXekzsECCLv+y2OJUsRodjqoSfwHkIX42VUFtUzg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +engine.io-parser@~5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" + integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== + +engine.io@~6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.0.tgz#003bec48f6815926f2b1b17873e576acd54f41d0" + integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg== + 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" + +enhanced-resolve@^5.10.0: + version "5.13.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz#26d1ecc448c02de997133217b5c1053f34a0a275" + integrity sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== + +envinfo@^7.7.3: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + +estree-walker@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + 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" + +express@^4.17.3: + version "4.18.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" + integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== + 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" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + 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" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + 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" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +format-util@1.0.5, format-util@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-monkey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + 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" + +glob@^7.1.3, glob@^7.1.6, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +google-protobuf@3.12.2: + version "3.12.2" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" + integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-middleware@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + 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" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-builtin-module@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + +is-core-module@^2.11.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" + integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== + dependencies: + has "^1.0.3" + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-reference@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + dependencies: + "@types/estree" "*" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^26.2.1: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +karma-chrome-launcher@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz#baca9cc071b1562a1db241827257bfe5cab597ea" + integrity sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ== + dependencies: + which "^1.2.1" + +karma-mocha@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" + integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== + dependencies: + minimist "^1.2.3" + +karma-sourcemap-loader@0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz#d4bae72fb7a8397328a62b75013d2df937bdcf9c" + integrity sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g== + dependencies: + graceful-fs "^4.1.2" + +karma-webpack@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" + integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + webpack-merge "^4.1.5" + +karma@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.0.tgz#82652dfecdd853ec227b74ed718a997028a99508" + integrity sha512-s8m7z0IF5g/bS5ONT7wsOavhW4i4aFkzD4u4wgzAQWT4HGUeWI3i21cK2Yz6jndMAeHETp5XuNsRoyGJZXVd4w== + 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" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.4.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.6.1.tgz#48f23de8a87d2f5ffd3d913f24ca9ce77895272f" + integrity sha512-J8VYFH2UQq/xucdNu71io4Fo+purYYudyErgBbswWKO0MC6QVOERRomt5su/z6d3RJSmLyTGmXl3Q/XjKCf+/A== + dependencies: + date-format "^4.0.13" + debug "^4.3.4" + flatted "^3.2.6" + rfdc "^1.3.0" + streamroller "^3.1.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +make-plural@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-6.2.2.tgz#beb5fd751355e72660eeb2218bb98eec92853c6c" + integrity sha512-8iTuFioatnTTmb/YJjywkVIHLjcwkFD9Ms0JpxjEm9Mo8eQYkh1z+55dwv4yc1jQ8ftVBxWQbihvZL1DfzGGWA== + +make-plural@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-7.1.0.tgz#8a0381ff8c9be4f074e0acdc42ec97639c2344f9" + integrity sha512-PKkwVlAxYVo98NrbclaQIT4F5Oy+X58PZM5r2IwUSCe3syya6PXkIRCn2XCdz7p58Scgpp50PBeHmepXVDG3hg== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.3: + version "3.4.7" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.7.tgz#e5252ad2242a724f938cb937e3c4f7ceb1f70e5a" + integrity sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw== + dependencies: + fs-monkey "^1.0.3" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz#9a1251d15f2035c342d99a468ab9da7a0451b71e" + integrity sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.3, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9" + integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +moo@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" + integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.12" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz#2efae5ffab3c8bfb2b7fbf0c426e3bca616c4abb" + integrity sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.4.19: + version "8.4.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" + integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.10.3: + version "6.10.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== + dependencies: + side-channel "^1.0.4" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.1: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + 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" + +readable-stream@^3.0.6: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.17.0, resolve@^1.19.0: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.9.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup-plugin-sourcemaps@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz#bf93913ffe056e414419607f1d02780d7ece84ed" + integrity sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw== + dependencies: + "@rollup/pluginutils" "^3.0.9" + source-map-resolve "^0.6.0" + +rollup-plugin-terser@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" + integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== + dependencies: + "@babel/code-frame" "^7.10.4" + jest-worker "^26.2.1" + serialize-javascript "^4.0.0" + terser "^5.0.0" + +rollup@^2.68.0: + version "2.79.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" + integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== + optionalDependencies: + fsevents "~2.3.2" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-identifier@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb" + integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== + dependencies: + node-forge "^1" + +semver@^7.3.8: + version "7.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + 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" + +serialize-javascript@6.0.0, serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + 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" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +socket.io-adapter@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" + integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== + +socket.io-parser@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" + integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.4.1: + version "4.5.2" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.2.tgz#1eb25fd380ab3d63470aa8279f8e48d922d443ac" + integrity sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ== + 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" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.0.tgz#bdc6b118bc6c87ee4d8d851f2d4efcc5abdb2ef5" + integrity sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw== + dependencies: + abab "^2.0.6" + iconv-lite "^0.6.3" + source-map-js "^1.0.2" + +source-map-resolve@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" + integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + 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" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + 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" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +streamroller@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.2.tgz#abd444560768b340f696307cf84d3f46e86c0e63" + integrity sha512-wZswqzbgGGsXYIrBYhOE0yP+nQ6XRk7xDcYwuQAGTYXdyAUmvgVFE0YU1g5pvQT0m7GBaQfYcSnlHbapuK0H0A== + dependencies: + date-format "^4.0.13" + debug "^4.3.4" + fs-extra "^8.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + 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" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" + integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== + +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.1.3: + version "5.3.6" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c" + integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ== + 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" + +terser@^5.0.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.1.tgz#948f10830454761e2eeedc6debe45c532c83fd69" + integrity sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +terser@^5.14.1: + version "5.15.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425" + integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +tslib@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + +typescript@4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +typescript@^3.7.2: + version "3.9.10" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" + integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== + +ua-parser-js@^0.7.30: + version "0.7.31" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.8.tgz#2f0b711327668eee01bbecddcf4a7c7954a7f8e2" + integrity sha512-GHg7C4M7oJSJYW/ED/5QOJ7nL/E0lwTOBGsOorA7jqHr8ExUhPfwAotIAmdSw/LWv3SMLSNpzTAgeLG9zaZKTA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webpack-cli@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + colorette "^2.0.14" + commander "^7.0.0" + cross-spawn "^7.0.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.9.3: + version "4.9.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz#2360a5d6d532acb5410a668417ad549ee3b8a3c9" + integrity sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw== + 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" + +webpack-merge@^4.1.5: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-merge@^5.7.3: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@5.74.0: + version "5.74.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980" + integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== + 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" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +ws@^8.4.2: + version "8.8.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0" + integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA== + +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0, yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + 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" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==