Initial commit

This commit is contained in:
jeobeardy committed 2024-08-16 10:50:57 +02:00
commit 2550140811
94 files changed
+10844

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Kotlin ###
.kotlin
.env*
+67
View File
@@ -0,0 +1,67 @@
plugins {
id("org.springframework.boot") version "3.3.0"
id("io.spring.dependency-management") version "1.1.5"
kotlin("plugin.jpa") version "1.9.24"
kotlin("jvm") version "1.9.24"
kotlin("plugin.spring") version "1.9.24"
kotlin("plugin.allopen") version "1.9.22"
}
group = "at.eisibaer"
version = "0.0.1-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
val jjwtVersion: String = "0.12.6";
val bcVersion: String = "1.78.1";
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("io.jsonwebtoken:jjwt-api:$jjwtVersion")
implementation("org.bouncycastle:bcprov-jdk18on:$bcVersion")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
runtimeOnly("io.jsonwebtoken:jjwt-impl:$jjwtVersion")
runtimeOnly("io.jsonwebtoken:jjwt-jackson:$jjwtVersion")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.springframework.security:spring-security-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
allOpen {
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.Embeddable")
annotation("jakarta.persistence.MappedSuperclass")
}
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+249
View File
@@ -0,0 +1,249 @@
#!/bin/sh
#
# 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.
# You may obtain a copy of the License at
#
# https://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.
#
##############################################################################
#
# 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/HEAD/platforms/jvm/plugins-application/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
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
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
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 ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
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
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
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" || "$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
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
# 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
fi
# 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"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
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.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+92
View File
@@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
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!
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
:omega
+1
View File
@@ -0,0 +1 @@
rootProject.name = "jeobeardy"
@@ -0,0 +1,13 @@
package at.eisibaer.jbear2
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.runApplication
@SpringBootApplication
@ConfigurationPropertiesScan(basePackages = ["at.eisibaer.jbear2.config"])
class JeobeardyApplication
fun main(args: Array<String>) {
runApplication<JeobeardyApplication>(*args)
}
@@ -0,0 +1,12 @@
package at.eisibaer.jbear2.config
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties("application")
data class ApplicationProperties(
val corsAllowedOrigins: List<String>,
val corsAllowedMethods: List<String>,
val jwtCookieName: String,
val jwtExpirationMs: Long,
val jwtSecret: String,
)
@@ -0,0 +1,51 @@
package at.eisibaer.jbear2.config
import jakarta.servlet.http.HttpServletRequest
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.Resource
import org.springframework.lang.Nullable
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
import org.springframework.web.servlet.resource.PathResourceResolver
import org.springframework.web.servlet.resource.ResourceResolverChain
@Configuration
class SpringConfiguration(
private val applicationProperties: ApplicationProperties
) : WebMvcConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
this.serveDirectory(registry, "/", "classpath:/static/")
}
private fun serveDirectory(registry: ResourceHandlerRegistry, endpoint: String, location: String){
val endpointPatterns: Array<String>;
if (endpoint.endsWith("/") ){
endpointPatterns = arrayOf(endpoint.substring(0, endpoint.length - 1), endpoint, "$endpoint**")
} else {
endpointPatterns = arrayOf(endpoint, "$endpoint/", "$endpoint/**")
}
registry
.addResourceHandler(*endpointPatterns)
.addResourceLocations( if( location.endsWith("/") ) location else "$location/")
.resourceChain(true)
.addResolver(object : PathResourceResolver(){
override fun resolveResource( @Nullable request: HttpServletRequest?, requestPath: String, locations: MutableList<out Resource>, chain: ResourceResolverChain ): Resource? {
val resource: Resource? = super.resolveResource(request, requestPath, locations, chain);
if( resource != null ){
return resource;
}
return super.resolveResource(request, "/index.html", locations, chain);
}
})
}
override fun addCorsMappings(registry: CorsRegistry) {
registry
.addMapping("/api/**")
.allowedOrigins(*applicationProperties.corsAllowedOrigins.map { it }.toTypedArray())
.allowedMethods(*applicationProperties.corsAllowedMethods.map { it }.toTypedArray())
}
}
@@ -0,0 +1,21 @@
package at.eisibaer.jbear2.config
import org.springframework.context.annotation.Configuration
import org.springframework.messaging.simp.config.MessageBrokerRegistry
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker
import org.springframework.web.socket.config.annotation.StompEndpointRegistry
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer
@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
registry.enableSimpleBroker("/game");
registry.setApplicationDestinationPrefixes("/app");
}
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry.addEndpoint("/websocket")
}
}
@@ -0,0 +1,6 @@
package at.eisibaer.jbear2.dto.auth
data class LoginDto(
val username: String,
val password: String,
)
@@ -0,0 +1,6 @@
package at.eisibaer.jbear2.dto.auth
data class LoginResponseDto(
val username: String,
val profilePicture: String,
)
@@ -0,0 +1,11 @@
package at.eisibaer.jbear2.dto.message
import lombok.AllArgsConstructor
@AllArgsConstructor
data class GenericMessage (
var name: String? = "",
var content: String? = "",
)
@@ -0,0 +1,87 @@
package at.eisibaer.jbear2.endpoint
import at.eisibaer.jbear2.dto.auth.LoginDto
import at.eisibaer.jbear2.dto.auth.LoginResponseDto
import at.eisibaer.jbear2.model.Board
import at.eisibaer.jbear2.model.User
import at.eisibaer.jbear2.repository.UserRepository
import at.eisibaer.jbear2.security.jwt.JwtUtils
import at.eisibaer.jbear2.security.userdetail.UserDetailsImpl
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.HttpHeaders
import org.springframework.http.ResponseCookie
import org.springframework.http.ResponseEntity
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
@Controller
@RequestMapping("/api/auth")
class AuthEndpoint(
val authenticationManager: AuthenticationManager,
val userRepository: UserRepository,
val encoder: PasswordEncoder,
val jwtUtils: JwtUtils,
) {
private val log: Logger = LoggerFactory.getLogger(AuthEndpoint::class.java);
val strResponseSuccess: String = "Sending back success response";
@PostMapping("/signup")
fun signupUser(@RequestBody loginDto: LoginDto): ResponseEntity<String>{
log.info("Endpoint singupUser called");
log.debug("signup Request with username: {}", loginDto.username);
if( userRepository.existsByUsername(loginDto.username)){
log.info("Username was already taken");
ResponseEntity.badRequest().body("Username already taken");
}
val user = User(loginDto.username, encoder.encode( loginDto.password), ArrayList(), null, null );
userRepository.save(user);
log.info(strResponseSuccess);
return ResponseEntity.ok().body("User registered successfully");
}
@PostMapping("/login")
fun loginUser(@RequestBody loginDto: LoginDto): ResponseEntity<LoginResponseDto>{
log.info("Endpoint loginUser called");
log.debug("login Request with username: {}", loginDto.username);
val authentication = authenticationManager.authenticate(
UsernamePasswordAuthenticationToken(
loginDto.username,
loginDto.password
)
)
SecurityContextHolder.getContext().authentication = authentication;
val userDetails: UserDetailsImpl = authentication.principal as UserDetailsImpl;
val jwtCookie = jwtUtils.generateJwtCookie(userDetails);
log.info(strResponseSuccess);
return ResponseEntity.ok()
.header( HttpHeaders.SET_COOKIE, jwtCookie.toString() )
.body( LoginResponseDto(userDetails.username, userDetails.getProfilePictureFilename()))
}
@PostMapping("signout")
fun logoutUser(): ResponseEntity<String>{
log.info("Endpoint logoutUser called");
val cookie: ResponseCookie = jwtUtils.getCleanJwtCookie();
log.info(strResponseSuccess);
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.body("Logged out");
}
}
@@ -0,0 +1,9 @@
package at.eisibaer.jbear2.endpoint
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
@Controller
@RequestMapping("/api/board")
class BoardEndpoint {
}
@@ -0,0 +1,19 @@
package at.eisibaer.jbear2.endpoint
import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.handler.annotation.SendTo
import at.eisibaer.jbear2.dto.message.GenericMessage
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/game")
class GameEndpoint {
@MessageMapping("/player/join")
@SendTo("/player/joined")
fun playerJoining(playerJoiningMessage: GenericMessage): GenericMessage{
return playerJoiningMessage.copy(playerJoiningMessage.name, "Joined");
}
}
@@ -0,0 +1,23 @@
package at.eisibaer.jbear2.endpoint
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/user")
class UserEndpoint {
val log: Logger = LoggerFactory.getLogger(UserEndpoint::class.java);
@GetMapping("/test/{pathVar}")
fun testEndpoint(@PathVariable pathVar: String, @RequestParam param1: String): ResponseEntity<String>{
log.info("test Endpoint!");
return ResponseEntity.ok(param1);
}
}
@@ -0,0 +1,25 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "answers", indexes = [
Index(name = "fk_board_entry_to_answer", columnList = "fk_board_entry")
])
data class Answer(
@Column(name = "text", nullable = false, unique = false)
val text: String,
@OneToOne
@JoinColumn(name = "fk_image_file", referencedColumnName = "id")
val image: ImageFile?,
@OneToOne
@JoinColumn(name="fk_board_entry", referencedColumnName = "id")
val boardEntry: BoardEntry?,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,24 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "boards", indexes = [
Index(name = "fk_owner_of_board", columnList = "fk_owned_by")
])
data class Board(
@OneToMany(mappedBy = "board")
val categories: List<Category>,
@Column(name = "board_name", nullable = false, unique = false)
val boardName: String,
@ManyToOne
@JoinColumn(name="fk_owned_by", referencedColumnName = "id")
val owner: User,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,27 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "board_entries", indexes = [
Index(name = "fk_category_to_board_entry", columnList = "fk_category")
])
data class BoardEntry(
@Column(name = "name", nullable = false, unique = false)
val name: String,
@OneToMany(mappedBy = "boardEntry")
val questions: List<Question>,
@OneToOne
val answer: Answer,
@ManyToOne
@JoinColumn(name = "fk_category", referencedColumnName = "id")
val category: Category?,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,27 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "categories", indexes = [
Index(name = "fk_category_to_board", columnList = "fk_board")
])
data class Category (
@Column(name = "name", nullable = false, unique = false)
val name: String,
@Column(name = "description", nullable = false, unique = false)
val description: String,
@OneToMany(mappedBy = "category")
val boardEntries: List<BoardEntry>,
@ManyToOne
@JoinColumn(name = "fk_board", referencedColumnName = "id")
val board: Board,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,51 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
import org.springframework.data.annotation.CreatedDate
import java.time.Instant
@Entity
@Table(name = "games", indexes = [
Index(name = "fk_board_to_game", columnList = "fk_board"),
Index(name = "fk_host_to_game", columnList = "fk_host_user"),
Index(name = "fk_choosing_player_to_game", columnList = "fk_player_currently_choosing")
])
data class Game(
@Column(name = "invite_code", nullable = false, unique = true)
val inviteCode: String,
@ManyToOne
@JoinColumn(name = "fk_board", referencedColumnName = "id")
val board: Board,
@OneToOne
@JoinColumn(name="fk_host_user", referencedColumnName = "id")
val host: User,
@OneToMany(mappedBy = "currentGame")
val players: List<Player>,
@OneToOne
@JoinColumn(name="fk_player_currently_choosing", referencedColumnName = "id")
val currentlyChoosingPlayer: Player,
@ManyToMany
@JoinTable(
name = "answered_board_entries_in_games",
joinColumns = [JoinColumn(name = "fk_game")],
inverseJoinColumns = [JoinColumn(name = "fk_board_entry")]
)
val alreadyAnsweredEntries: List<BoardEntry>,
@Column(name = "accepting_answers", nullable = false, unique = false)
val acceptingAnswers: Boolean? = false,
@CreatedDate
@Column(name = "created_timestamp", nullable = false, unique = false)
val createdTimestamp: Instant,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,34 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
import java.util.UUID
@Entity
@Table(name = "image_files", indexes = [
Index(name = "fk_owner_to_image_file", columnList = "fk_owned_by")
])
data class ImageFile (
@Column(name = "uuid", nullable = false, unique = true)
val uuid: UUID,
@Column(name = "filename", nullable = false, unique = false)
val filename: String,
@Column(name = "hash", nullable = false, unique = false)
val hash: String,
@ManyToOne
@JoinColumn(name="fk_owned_by", referencedColumnName = "id")
val owner: User,
@OneToOne
val question: Question?,
@OneToOne
val answer: Answer?,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,28 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "players", indexes = [
Index(name = "fk_current_game_to_player", columnList = "fk_current_game"),
Index(name = "fk_name_to_player", columnList = "name"),
])
data class Player(
@Column(name = "name", nullable = false, unique = false)
val name: String,
@ManyToOne
@JoinColumn(name = "fk_current_game", referencedColumnName = "id")
val currentGame: Game,
@Column(name = "is_allowed_to_answer", nullable = false, unique = false)
val allowedToAnswer: Boolean? = false,
@Column(name = "points", nullable = false, unique = false)
val points: Int? = 0,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,31 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "questions", indexes = [
Index(name = "fk_board_entry_to_question", columnList = "fk_board_entry"),
Index(name = "fk_image_file_to_question", columnList = "fk_image"),
Index(name = "fk_question_type_to_question", columnList = "fk_question_type"),
])
data class Question(
@Column(name = "text", nullable = false, unique = false)
val text: String,
@ManyToOne
@JoinColumn(name = "fk_question_type", referencedColumnName = "id")
val questionType: QuestionType,
@OneToOne
@JoinColumn(name = "fk_image", referencedColumnName = "id")
val image: ImageFile?,
@ManyToOne
@JoinColumn(name = "fk_board_entry", referencedColumnName = "id")
val boardEntry: BoardEntry?,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,21 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "question_types")
data class QuestionType(
@Column(name = "title", nullable = false, unique = true)
val title: String,
@Column(name = "description", nullable = false, unique = true)
val description: String,
@Column(name = "active", nullable = false, unique = false)
val active: Boolean,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,28 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "users", indexes = [
Index(name = "fk_profile_picture_to_user", columnList = "fk_profile_picture"),
Index(name = "username_to_user", columnList = "username"),
])
data class User(
@Column(name = "username", nullable = false, unique = true)
var username: String,
@Column(name = "password", nullable = false, unique = false)
var password: String,
@OneToMany(mappedBy = "owner")
val boards: List<Board>,
@OneToOne
@JoinColumn(name = "fk_profile_picture", referencedColumnName = "id")
var profilePicture: ImageFile?,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)
@@ -0,0 +1,14 @@
package at.eisibaer.jbear2.repository
import at.eisibaer.jbear2.model.User
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
import java.util.*
@Repository
interface UserRepository : JpaRepository<User, Long> {
fun findUserByUsername(username: String): Optional<User>;
fun existsByUsername(username: String): Boolean;
}
@@ -0,0 +1,126 @@
package at.eisibaer.jbear2.security
import at.eisibaer.jbear2.security.jwt.AuthTokenFilter
import jakarta.servlet.FilterChain
import jakarta.servlet.ServletException
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import org.springframework.security.web.csrf.*
import org.springframework.util.StringUtils
import org.springframework.web.filter.OncePerRequestFilter
import java.io.IOException
import java.util.function.Supplier
@Configuration
@EnableMethodSecurity
class SecurityConfiguration(
private val userDetailService: UserDetailsService,
private val unauthorizedHandler: AuthTokenFilter,
) {
final val log: Logger = LoggerFactory.getLogger(SecurityConfiguration::class.java);
@Bean
fun securityFilterChain(httpSecurity: HttpSecurity): SecurityFilterChain {
return httpSecurity
.csrf { config ->
config
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(SpaCsrfTokenRequestHandler())
}
.addFilterAfter(CsrfCookieFilter(), BasicAuthenticationFilter::class.java)
.authorizeHttpRequests { config ->
config
.requestMatchers("/api/auth/*").permitAll()
.requestMatchers("/api/**").authenticated()
.requestMatchers("/profile").authenticated()
.requestMatchers("/**").permitAll()
}
.sessionManagement { config: SessionManagementConfigurer<HttpSecurity?> ->
config.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
.authenticationProvider(authenticationProvider())
.addFilterBefore(unauthorizedHandler, UsernamePasswordAuthenticationFilter::class.java)
.build()
}
class SpaCsrfTokenRequestHandler : CsrfTokenRequestAttributeHandler() {
private val delegate: CsrfTokenRequestHandler = XorCsrfTokenRequestAttributeHandler()
override fun handle(request: HttpServletRequest, response: HttpServletResponse, csrfToken: Supplier<CsrfToken>) {
/*
* Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of
* the CsrfToken when it is rendered in the response body.
*/
delegate.handle(request, response, csrfToken)
}
override fun resolveCsrfTokenValue(request: HttpServletRequest, csrfToken: CsrfToken): String? {
/*
* If the request contains a request header, use CsrfTokenRequestAttributeHandler
* to resolve the CsrfToken. This applies when a single-page application includes
* the header value automatically, which was obtained via a cookie containing the
* raw CsrfToken.
*/
return if (StringUtils.hasText(request.getHeader(csrfToken.headerName))) {
super.resolveCsrfTokenValue(request, csrfToken)
} else {
/*
* In all other cases (e.g. if the request contains a request parameter), use
* XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
* when a server-side rendered form includes the _csrf request parameter as a
* hidden input.
*/
delegate.resolveCsrfTokenValue(request, csrfToken)
}
}
}
class CsrfCookieFilter : OncePerRequestFilter() {
@Throws(ServletException::class, IOException::class)
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
val csrfToken = request.getAttribute("_csrf") as CsrfToken
// Render the token value to a cookie by causing the deferred token to be loaded
csrfToken.token
filterChain.doFilter(request, response)
}
}
@Bean
fun passwordEncoder() : PasswordEncoder {
return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
}
@Bean
fun authenticationProvider(): DaoAuthenticationProvider{
val authProvider: DaoAuthenticationProvider = DaoAuthenticationProvider()
authProvider.setUserDetailsService(userDetailService)
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
fun authenticationManager(authConfig: AuthenticationConfiguration): AuthenticationManager{
return authConfig.authenticationManager;
}
}
@@ -0,0 +1,23 @@
package at.eisibaer.jbear2.security.jwt
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.AuthenticationEntryPoint
class AuthEntryPointJwt: AuthenticationEntryPoint {
val log: Logger = LoggerFactory.getLogger(AuthEntryPointJwt::class.java);
override fun commence(
request: HttpServletRequest?,
response: HttpServletResponse?,
authException: AuthenticationException?
) {
log.error("Unauthorized error: {}", authException?.message);
response?.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
}
}
@@ -0,0 +1,51 @@
package at.eisibaer.jbear2.security.jwt
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
@Component
class AuthTokenFilter(
private var jwtUtils: JwtUtils?,
private var userDetailService: UserDetailsService?,
): OncePerRequestFilter() {
val log: Logger = LoggerFactory.getLogger(AuthTokenFilter::class.java);
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
try{
val jwt: String? = parseJwt(request);
if( jwt != null && jwtUtils!!.validateJwt(jwt) ){
val username: String = jwtUtils!!.getUserNameFromJwt(jwt);
val userDetails: UserDetails = userDetailService!!.loadUserByUsername( username );
val authentication = UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities);
authentication.details = WebAuthenticationDetailsSource().buildDetails(request);
SecurityContextHolder.getContext().authentication = authentication;
}
} catch ( e: Exception ){
log.error("Cannot set user authentication", e);
}
filterChain.doFilter(request, response);
}
private fun parseJwt(request: HttpServletRequest): String?{
return jwtUtils!!.getJwtFromCookies(request);
}
}
@@ -0,0 +1,75 @@
package at.eisibaer.jbear2.security.jwt
import at.eisibaer.jbear2.config.ApplicationProperties
import at.eisibaer.jbear2.security.userdetail.UserDetailsImpl
import io.jsonwebtoken.JwtException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.UnsupportedJwtException
import io.jsonwebtoken.io.Decoders
import io.jsonwebtoken.security.Keys
import jakarta.servlet.http.HttpServletRequest
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.ResponseCookie
import org.springframework.stereotype.Component
import org.springframework.web.util.WebUtils
import java.util.Date
import javax.crypto.SecretKey
@Component
class JwtUtils(
private val applicationProperties: ApplicationProperties
) {
private val log: Logger = LoggerFactory.getLogger(JwtUtils::class.java);
fun getJwtFromCookies(request: HttpServletRequest): String?{
return WebUtils.getCookie(request, applicationProperties.jwtCookieName)?.value;
}
fun generateJwtCookie(userPrincipal: UserDetailsImpl): ResponseCookie{
val jwt: String = generateTokenFromUsername(userPrincipal.username)
return ResponseCookie.from(applicationProperties.jwtCookieName, jwt)
.path("/api")
.maxAge(applicationProperties.jwtExpirationMs/1000)
.httpOnly(true)
.build();
}
fun getCleanJwtCookie(): ResponseCookie {
return ResponseCookie.from(applicationProperties.jwtCookieName, "")
.path("/api")
.build();
}
fun getUserNameFromJwt(token: String): String{
return Jwts.parser().verifyWith(key()).build().parseSignedClaims(token).payload.subject;
}
fun key(): SecretKey{
return Keys.hmacShaKeyFor(Decoders.BASE64.decode(applicationProperties.jwtSecret));
}
fun generateTokenFromUsername(username: String): String{
return Jwts.builder()
.subject(username)
.issuedAt(Date())
.expiration(Date(Date().time + applicationProperties.jwtExpirationMs))
.signWith(key())
.compact();
}
fun validateJwt(authToken: String): Boolean{
try {
Jwts.parser().verifyWith(key()).build().parseSignedClaims(authToken);
return true;
} catch (e: UnsupportedJwtException) {
log.error("UnsupportedJwtException {}", e.message);
} catch (e: IllegalArgumentException) {
log.error("IllegalArgumentException {}", e.message);
} catch (e: JwtException) {
log.error("JwtException {}", e.message);
}
return false;
}
}
@@ -0,0 +1,28 @@
package at.eisibaer.jbear2.security.userdetail
import at.eisibaer.jbear2.repository.UserRepository
import at.eisibaer.jbear2.model.User
import lombok.AllArgsConstructor
import lombok.NoArgsConstructor
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.stereotype.Component
@AllArgsConstructor
@NoArgsConstructor
@Component
class UserDetailServiceImpl(
val userRepository: UserRepository,
): UserDetailsService {
override fun loadUserByUsername(username: String?): UserDetailsImpl {
val user: User = userRepository.findUserByUsername( username ?: "" ).orElseThrow { UsernameNotFoundException("User not found by username \"$username\"") }
return UserDetailsImpl(
user.id!!,
user.username,
user.password,
user.profilePicture?.filename,
);
}
}
@@ -0,0 +1,67 @@
package at.eisibaer.jbear2.security.userdetail
import com.fasterxml.jackson.annotation.JsonIgnore
import lombok.Data
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import java.util.Collections
@Data
class UserDetailsImpl(
private val id: Long,
private val username: String,
@JsonIgnore
private val password: String,
private val profilePictureFilename: String?,
): UserDetails {
override fun getAuthorities(): MutableCollection<out GrantedAuthority> {
return Collections.emptyList();
}
override fun getPassword(): String {
return password;
}
override fun getUsername(): String {
return username;
}
fun getProfilePictureFilename(): String {
return profilePictureFilename ?: "";
}
fun getId(): Long{
return id;
}
override fun isAccountNonExpired(): Boolean {
return true
}
override fun isAccountNonLocked(): Boolean {
return true
}
override fun isCredentialsNonExpired(): Boolean {
return true
}
override fun isEnabled(): Boolean {
return true
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as UserDetailsImpl
return id == other.id
}
override fun hashCode(): Int {
return id.hashCode()
}
}
@@ -0,0 +1,13 @@
logging:
level:
org:
springframework:
security: "DEBUG"
spring:
datasource:
url: jdbc:postgresql://localhost:5499/jeobeardy?currentSchema=jeobeardy-app
username: ${PG_USER}
password: ${PG_PASSWORD}
application:
cors-allowed-origins: [ "http://localhost:5173/" ]
@@ -0,0 +1,8 @@
spring:
datasource:
url: jdbc:postgresql://localhost:5499/jeobeardy?currentSchema=jeobeardy-app
username: ${PG_USER}
password: ${PG_PASSWORD}
application:
cors-allowed-origins: []
+23
View File
@@ -0,0 +1,23 @@
spring:
application:
name: "jeobeardy"
jpa:
show-sql: true
hibernate:
auto-ddl: create
generate-ddl: true
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
default-schema: jeobeardy-app
open-in-view: false
server:
address: localhost
port: 8008
application:
cors-allowed-methods: ["GET", "POST", "DELETE", "OPTIONS"]
jwt-cookie-name: "user_jwt"
jwt-expiration-ms: 86400000 #1000 * 60 * 60 * 24 = 1 day
jwt-secret: ${JWT_SECRET}
Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

@@ -0,0 +1,5 @@
@charset "UTF-8";.home-player-join-row[data-v-6c838f03]{background-image:url(/assets/OldInGameBlurredRotated-Bc8vmN0_.jpeg);background-repeat:no-repeat;background-size:cover}.preserve-breaks{white-space:preserve-breaks}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width: 576px){.container-sm,.container{max-width:540px}}@media (min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media (min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media (min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media (min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#e86a92;border-color:#e86a92;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23f4b5c9'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.was-validated .form-control:valid,.form-control.is-valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' dLine truncated
* Bootstrap v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-primary: #e86a92;--bs-secondary: #3e92cc;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #edf2f4;--bs-dark: #2b2d42;--bs-gray: #adb5bd;--bs-dark-accented: #252638;--bs-rich-black: #2d3543;--bs-primary-rgb: 232, 106, 146;--bs-secondary-rgb: 62, 146, 204;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 237, 242, 244;--bs-dark-rgb: 43, 45, 66;--bs-gray-rgb: 173, 181, 189;--bs-dark-accented-rgb: 37, 38, 56;--bs-rich-black-rgb: 45, 53, 67;--bs-primary-text-emphasis: #5d2a3a;--bs-secondary-text-emphasis: #193a52;--bs-success-text-emphasis: #0a3622;--bs-info-text-emphasis: #055160;--bs-warning-text-emphasis: #664d03;--bs-danger-text-emphasis: #58151c;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #fae1e9;--bs-secondary-bg-subtle: #d8e9f5;--bs-success-bg-subtle: #d1e7dd;--bs-info-bg-subtle: #cff4fc;--bs-warning-bg-subtle: #fff3cd;--bs-danger-bg-subtle: #f8d7da;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #f6c3d3;--bs-secondary-border-subtle: #b2d3eb;--bs-success-border-subtle: #a3cfbb;--bs-info-border-subtle: #9eeaf9;--bs-warning-border-subtle: #ffe69c;--bs-danger-border-subtle: #f1aeb5;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, .15), rgba(255, 255, 255, 0));--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #edf2f4;--bs-body-bg-rgb: 237, 242, 244;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, .75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #d5dadc;--bs-secondary-bg-rgb: 213, 218, 220;--bs-tertiary-color: rgba(33, 37, 41, .5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #e86a92;--bs-link-color-rgb: 232, 106, 146;--bs-link-decoration: underline;--bs-link-hover-color: #ba5575;--bs-link-hover-color-rgb: 186, 85, 117;--bs-code-color: #d63384;--bs-highlight-color: #212529;--bs-highlight-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, .175);--bs-border-radius: .375rem;--bs-border-radius-sm: .25rem;--bs-border-radius-lg: .5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-box-shadow-sm: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, .175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .075);--bs-focus-ring-width: .25rem;--bs-focus-ring-opacity: .25;--bs-focus-ring-color: rgba(232, 106, 146, .25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #2b2d42;--bs-body-bg-rgb: 43, 45, 66;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, .75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #252638;--bs-secondary-bg-rgb: 37, 38, 56;--bs-tertiary-color: rgba(222, 226, 230, .5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #f1a6be;--bs-secondary-text-emphasis: #8bbee0;--bs-success-text-emphasis: #75b798;--bs-info-text-emphasis: #6edff6;--bs-warning-text-emphasis: #ffda6a;--bs-danger-text-emphasis: #ea868f;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #2e151d;--bs-secondary-bg-subtle: #0c1d29;--bs-success-bg-subtle: #051b11;--bs-info-bg-subtle: #032830;--bs-warning-bg-subtle: #332701;--bs-danger-bg-Line truncated
@@ -0,0 +1,813 @@
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(s){if(s.ep)return;s.ep=!0;const i=n(s);fetch(s.href,i)}})();/**
* @vue/shared v3.4.29
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**//*! #__NO_SIDE_EFFECTS__ */function Fl(e,t){const n=new Set(e.split(","));return r=>n.has(r)}const ke={},Mr=[],Ct=()=>{},h_=()=>!1,go=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),jl=e=>e.startsWith("onUpdate:"),Ze=Object.assign,Ul=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},p_=Object.prototype.hasOwnProperty,we=(e,t)=>p_.call(e,t),ce=Array.isArray,Fr=e=>_o(e)==="[object Map]",mm=e=>_o(e)==="[object Set]",he=e=>typeof e=="function",Ge=e=>typeof e=="string",br=e=>typeof e=="symbol",Fe=e=>e!==null&&typeof e=="object",hm=e=>(Fe(e)||he(e))&&he(e.then)&&he(e.catch),pm=Object.prototype.toString,_o=e=>pm.call(e),g_=e=>_o(e).slice(8,-1),gm=e=>_o(e)==="[object Object]",Hl=e=>Ge(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Es=Fl(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),vo=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},__=/-(\w)/g,Xt=vo(e=>e.replace(__,(t,n)=>n?n.toUpperCase():"")),v_=/\B([A-Z])/g,rs=vo(e=>e.replace(v_,"-$1").toLowerCase()),bo=vo(e=>e.charAt(0).toUpperCase()+e.slice(1)),Qo=vo(e=>e?`on${bo(e)}`:""),Rn=(e,t)=>!Object.is(e,t),Di=(e,...t)=>{for(let n=0;n<e.length;n++)e[n](...t)},_m=(e,t,n,r=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:r,value:n})},Fa=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let tu;const vm=()=>tu||(tu=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Zn(e){if(ce(e)){const t={};for(let n=0;n<e.length;n++){const r=e[n],s=Ge(r)?w_(r):Zn(r);if(s)for(const i in s)t[i]=s[i]}return t}else if(Ge(e)||Fe(e))return e}const b_=/;(?![^(]*\))/g,y_=/:([^]+)/,E_=/\/\*[^]*?\*\//g;function w_(e){const t={};return e.replace(E_,"").split(b_).forEach(n=>{if(n){const r=n.split(y_);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function Nt(e){let t="";if(Ge(e))t=e;else if(ce(e))for(let n=0;n<e.length;n++){const r=Nt(e[n]);r&&(t+=r+" ")}else if(Fe(e))for(const n in e)e[n]&&(t+=n+" ");return t.trim()}const A_="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",T_=Fl(A_);function bm(e){return!!e||e===""}const ue=e=>Ge(e)?e:e==null?"":ce(e)||Fe(e)&&(e.toString===pm||!he(e.toString))?JSON.stringify(e,ym,2):String(e),ym=(e,t)=>t&&t.__v_isRef?ym(e,t.value):Fr(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,s],i)=>(n[Zo(r,i)+" =>"]=s,n),{})}:mm(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>Zo(n))}:br(t)?Zo(t):Fe(t)&&!ce(t)&&!gm(t)?String(t):t,Zo=(e,t="")=>{var n;return br(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/**
* @vue/reactivity v3.4.29
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/let yt;class Em{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=yt,!t&&yt&&(this.index=(yt.scopes||(yt.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=yt;try{return yt=this,t()}finally{yt=n}}}on(){yt=this}off(){yt=this.parent}stop(t){if(this._active){let n,r;for(n=0,r=this.effects.length;n<r;n++)this.effects[n].stop();for(n=0,r=this.cleanups.length;n<r;n++)this.cleanups[n]();if(this.scopes)for(n=0,r=this.scopes.length;n<r;n++)this.scopes[n].stop(!0);if(!this.detached&&this.parent&&!t){const s=this.parent.scopes.pop();s&&s!==this&&(this.parent.scopes[this.index]=s,s.index=this.index)}this.parent=void 0,this._active=!1}}}function Vl(e){return new Em(e)}function O_(e,t=yt){t&&t.active&&t.effects.push(e)}function wm(){return yt}function S_(e){yt&&yt.cleanups.push(e)}let ar;class Bl{constructor(t,n,r,s){this.fn=t,this.trigger=n,this.scheduler=r,this.active=!0,this.deps=[],this._dirtyLevel=5,this._trackId=0,this._runnings=0,this._shouldSchedule=!1,this._depsLength=0,O_(this,s)}get dirty(){if(this._dirtyLevel===2)return!1;if(this._dirtyLevel===3||this._dirtyLevel===4){this._dirtyLevel=1,Un();for(let t=0;t<this._depsLength;t++){const n=this.deps[t];if(n.computed){if(n.computed.effect._dirtyLevel===2)return!0;if(C_(n.computed),this._dirtyLevel>=5)break}}this._dirtyLevel===1&&(this._dirtyLevel=0),Hn()}return this._dirtyLevel>=5}set dirty(t){this._dirtyLevel=t?5:0}run(){if(this._dirtyLevel=0,!this.active)return this.fn();let t=Ln,n=ar;try{return Ln=!0,ar=this,this._runnings++,nu(this),this.fn()}finally{ru(this),this._runnings--,ar=n,Ln=t}}stop(){this.active&&(nu(this),ru(this),this.onStop&&this.onStop(),this.active=!1)}}function C_(e){return e.value}function nu(e){e._trackId++,e._depsLength=0}function ru(e){if(e.deps.length>e._depsLength){for(let t=e._depsLength;t<e.deps.length;t++)Am(e.deps[t],e);e.deps.length=e._depsLength}}function Am(e,t){const n=e.get(t);n!==void 0&&t._trackId!==n&&(e.delete(t),e.size===0&&e.cleanup())}let Ln=!0,ja=0;const Tm=[];function Un(){Tm.push(Ln),Ln=!1}function Hn(){const e=Tm.pop();Ln=e===void 0?!0:e}function Wl(){ja++}function Yl(){for(ja--;!ja&&Ua.length;)Ua.shift()()}function Om(e,t,n){if(t.get(e)!==e._trackId){t.set(e,e._trackId);const r=e.deps[e._depsLength];r!==t?(r&&Am(r,e),e.deps[e._depsLength++]=t):e._depsLength++}}const Ua=[];function Sm(e,t,n){Wl();for(const r of e.keys()){if(!e.computed&&r.computed&&e.get(r)===r._trackId&&r._runnings>0){r._dirtyLevel=2;continue}let s;r._dirtyLevel<t&&(s??(s=e.get(r)===r._trackId))&&(r._shouldSchedule||(r._shouldSchedule=r._dirtyLevel===0),r.computed&&r._dirtyLevel===2&&(r._shouldSchedule=!0),r._dirtyLevel=t),r._shouldSchedule&&(s??(s=e.get(r)===r._trackId))&&(r.trigger(),(!r._runnings||r.allowRecurse)&&r._dirtyLevel!==3&&(r._shouldSchedule=!1,r.scheduler&&Ua.push(r.scheduler)))}Yl()}const Cm=(e,t)=>{const n=new Map;return n.cleanup=e,n.computed=t,n},Xi=new WeakMap,lr=Symbol(""),Ha=Symbol("");function _t(e,t,n){if(Ln&&ar){let r=Xi.get(e);r||Xi.set(e,r=new Map);let s=r.get(n);s||r.set(n,s=Cm(()=>r.delete(n))),Om(ar,s)}}function on(e,t,n,r,s,i){const o=Xi.get(e);if(!o)return;let a=[];if(t==="clear")a=[...o.values()];else if(n==="length"&&ce(e)){const l=Number(r);o.forEach((u,c)=>{(c==="length"||!br(c)&&c>=l)&&a.push(u)})}else switch(n!==void 0&&a.push(o.get(n)),t){case"add":ce(e)?Hl(n)&&a.push(o.get("length")):(a.push(o.get(lr)),Fr(e)&&a.push(o.get(Ha)));break;case"delete":ce(e)||(a.push(o.get(lr)),Fr(e)&&a.push(o.get(Ha)));break;case"set":Fr(e)&&a.push(o.get(lr));break}Wl();for(const l of a)l&&Sm(l,5);Yl()}function N_(e,t){const n=Xi.get(e);return n&&n.get(t)}const L_=Fl("__proto__,__v_isRef,__isVue"),Nm=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(br)),su=I_();function I_(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=Ae(this);for(let i=0,o=this.length;i<o;i++)_t(r,"get",i+"");const s=r[t](...n);return s===-1||s===!1?r[t](...n.map(Ae)):s}}),["push","pop","shift","unshift","splice"].forEach(t=>{e[t]=function(...n){Un(),Wl();const r=Ae(this)[t].apply(this,n);return Yl(),Hn(),r}}),e}function P_(e){br(e)||(e=String(e));const t=Ae(this);return _t(t,"has",e),t.hasOwnProperty(e)}class Lm{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,r){const s=this._isReadonly,i=this._isShallow;if(n==="__v_isReactive")return!s;if(n==="__v_isReadonly")return s;if(n==="__v_isShallow")return i;if(n==="__v_raw")return r===(s?i?W_:xm:i?Rm:Pm).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(r)?t:void 0;const o=ce(t);if(!s){if(o&&we(su,n))return Reflect.get(su,n,r);if(n==="hasOwnProperty")return P_}const a=Reflect.get(t,n,r);return(br(n)?Nm.has(n):L_(n))||(s||_t(t,"get",n),i)?a:He(a)?o&&Hl(n)?a:a.value:Fe(a)?s?$m(a):Vn(a):a}}class Im extends Lm{constructor(t=!1){super(!1,t)}set(t,n,r,s){let i=t[n];if(!this._isShallow){const l=Vr(i);if(!Ji(rLine truncated
* @vue/runtime-core v3.4.29
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/function Pn(e,t,n,r){try{return r?e(...r):e()}catch(s){Eo(s,t,n)}}function Mt(e,t,n,r){if(he(e)){const s=Pn(e,t,n,r);return s&&hm(s)&&s.catch(i=>{Eo(i,t,n)}),s}if(ce(e)){const s=[];for(let i=0;i<e.length;i++)s.push(Mt(e[i],t,n,r));return s}}function Eo(e,t,n,r=!0){const s=t?t.vnode:null;if(t){let i=t.parent;const o=t.proxy,a=`https://vuejs.org/error-reference/#runtime-${n}`;for(;i;){const u=i.ec;if(u){for(let c=0;c<u.length;c++)if(u[c](e,o,a)===!1)return}i=i.parent}const l=t.appContext.config.errorHandler;if(l){Un(),Pn(l,null,10,[e,o,a]),Hn();return}}Z_(e,n,s,r)}function Z_(e,t,n,r=!0){console.error(e)}let Ds=!1,Va=!1;const rt=[];let Yt=0;const jr=[];let An=null,Qn=0;const Hm=Promise.resolve();let Ql=null;function Ms(e){const t=Ql||Hm;return e?t.then(this?e.bind(this):e):t}function ev(e){let t=Yt+1,n=rt.length;for(;t<n;){const r=t+n>>>1,s=rt[r],i=Fs(s);i<e||i===e&&s.pre?t=r+1:n=r}return t}function Zl(e){(!rt.length||!rt.includes(e,Ds&&e.allowRecurse?Yt+1:Yt))&&(e.id==null?rt.push(e):rt.splice(ev(e.id),0,e),Vm())}function Vm(){!Ds&&!Va&&(Va=!0,Ql=Hm.then(Wm))}function tv(e){const t=rt.indexOf(e);t>Yt&&rt.splice(t,1)}function nv(e){ce(e)?jr.push(...e):(!An||!An.includes(e,e.allowRecurse?Qn+1:Qn))&&jr.push(e),Vm()}function cu(e,t,n=Ds?Yt+1:0){for(;n<rt.length;n++){const r=rt[n];if(r&&r.pre){if(e&&r.id!==e.uid)continue;rt.splice(n,1),n--,r()}}}function Bm(e){if(jr.length){const t=[...new Set(jr)].sort((n,r)=>Fs(n)-Fs(r));if(jr.length=0,An){An.push(...t);return}for(An=t,Qn=0;Qn<An.length;Qn++){const n=An[Qn];n.active!==!1&&n()}An=null,Qn=0}}const Fs=e=>e.id==null?1/0:e.id,rv=(e,t)=>{const n=Fs(e)-Fs(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Wm(e){Va=!1,Ds=!0,rt.sort(rv);try{for(Yt=0;Yt<rt.length;Yt++){const t=rt[Yt];t&&t.active!==!1&&Pn(t,null,14)}}finally{Yt=0,rt.length=0,Bm(),Ds=!1,Ql=null,(rt.length||jr.length)&&Wm()}}function sv(e,t,...n){if(e.isUnmounted)return;const r=e.vnode.props||ke;let s=n;const i=t.startsWith("update:"),o=i&&t.slice(7);if(o&&o in r){const c=`${o==="modelValue"?"model":o}Modifiers`,{number:f,trim:d}=r[c]||ke;d&&(s=n.map(m=>Ge(m)?m.trim():m)),f&&(s=n.map(Fa))}let a,l=r[a=Qo(t)]||r[a=Qo(Xt(t))];!l&&i&&(l=r[a=Qo(rs(t))]),l&&Mt(l,e,6,s);const u=r[a+"Once"];if(u){if(!e.emitted)e.emitted={};else if(e.emitted[a])return;e.emitted[a]=!0,Mt(u,e,6,s)}}function Ym(e,t,n=!1){const r=t.emitsCache,s=r.get(e);if(s!==void 0)return s;const i=e.emits;let o={},a=!1;if(!he(e)){const l=u=>{const c=Ym(u,t,!0);c&&(a=!0,Ze(o,c))};!n&&t.mixins.length&&t.mixins.forEach(l),e.extends&&l(e.extends),e.mixins&&e.mixins.forEach(l)}return!i&&!a?(Fe(e)&&r.set(e,null),null):(ce(i)?i.forEach(l=>o[l]=null):Ze(o,i),Fe(e)&&r.set(e,o),o)}function wo(e,t){return!e||!go(t)?!1:(t=t.slice(2).replace(/Once$/,""),we(e,t[0].toLowerCase()+t.slice(1))||we(e,rs(t))||we(e,t))}let ct=null,Ao=null;function Qi(e){const t=ct;return ct=e,Ao=e&&e.type.__scopeId||null,t}function iv(e){Ao=e}function ov(){Ao=null}function er(e,t=ct,n){if(!t||e._n)return e;const r=(...s)=>{r._d&&Eu(-1);const i=Qi(t);let o;try{o=e(...s)}finally{Qi(i),r._d&&Eu(1)}return o};return r._n=!0,r._c=!0,r._d=!0,r}function ea(e){const{type:t,vnode:n,proxy:r,withProxy:s,propsOptions:[i],slots:o,attrs:a,emit:l,render:u,renderCache:c,props:f,data:d,setupState:m,ctx:p,inheritAttrs:v}=e,y=Qi(e);let w,S;try{if(n.shapeFlag&4){const A=s||r,C=A;w=Wt(u.call(C,A,c,f,m,d,p)),S=a}else{const A=t;w=Wt(A.length>1?A(f,{attrs:a,slots:o,emit:l}):A(f,null)),S=t.props?a:av(a)}}catch(A){Ts.length=0,Eo(A,e,1),w=ye(dr)}let E=w;if(S&&v!==!1){const A=Object.keys(S),{shapeFlag:C}=E;A.length&&C&7&&(i&&A.some(jl)&&(S=lv(S,i)),E=Br(E,S,!1,!0))}return n.dirs&&(E=Br(E,null,!1,!0),E.dirs=E.dirs?E.dirs.concat(n.dirs):n.dirs),n.transition&&(E.transition=n.transition),w=E,Qi(y),w}const av=e=>{let t;for(const n in e)(n==="class"||n==="style"||go(n))&&((t||(t={}))[n]=e[n]);return t},lv=(e,t)=>{const n={};for(const r in e)(!jl(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function cv(e,t,n){const{props:r,children:s,component:i}=e,{props:o,children:a,patchFlag:l}=t,u=i.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&l>=0){if(l&1024)return!0;if(l&16)return r?uu(r,o,u):!!o;if(l&8){const c=t.dynamicProps;for(let f=0;f<c.length;f++){const d=c[f];if(o[d]!==r[d]&&!wo(u,d))return!0}}}else return(s||a)&&(!a||!a.$stable)?!0:r===o?!1:r?o?uu(r,o,u):!0:!!o;return!1}function uu(e,t,n){const r=Object.keys(t);if(r.length!==Object.keys(e).length)return!0;for(let s=0;s<r.length;s++){const i=r[s];if(t[i]!==e[i]&&!wo(n,i))return!0}return!1}function uv({vnode:e,parent:t},n){for(;t;){const r=t.subTree;if(r.suspense&&r.suspense.activeBranch===e&&(r.el=e.el),r===e)(e=t.vnode).el=n,t=t.parent;else break}}const fv="components";function ec(e,t){return mv(fv,e,!0,t)||e}const dv=Symbol.for("v-ndc");function mv(e,t,n=!0,r=!1){const s=ct||Je;if(s){const i=s.type;{const a=sb(i,!1);if(a&&(a===t||a===Xt(t)||a===bo(Xt(t))))return i}const o=fu(s[e]||i[e],t)||fu(s.appContext[e],t);return!o&&r?i:o}}f Line truncated
* @vue/runtime-dom v3.4.29
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/const ab="http://www.w3.org/2000/svg",lb="http://www.w3.org/1998/Math/MathML",nn=typeof document<"u"?document:null,Ou=nn&&nn.createElement("template"),cb={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const s=t==="svg"?nn.createElementNS(ab,e):t==="mathml"?nn.createElementNS(lb,e):n?nn.createElement(e,{is:n}):nn.createElement(e);return e==="select"&&r&&r.multiple!=null&&s.setAttribute("multiple",r.multiple),s},createText:e=>nn.createTextNode(e),createComment:e=>nn.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>nn.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,s,i){const o=n?n.previousSibling:t.lastChild;if(s&&(s===i||s.nextSibling))for(;t.insertBefore(s.cloneNode(!0),n),!(s===i||!(s=s.nextSibling)););else{Ou.innerHTML=r==="svg"?`<svg>${e}</svg>`:r==="mathml"?`<math>${e}</math>`:e;const a=Ou.content;if(r==="svg"||r==="mathml"){const l=a.firstChild;for(;l.firstChild;)a.appendChild(l.firstChild);a.removeChild(l)}t.insertBefore(a,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},ub=Symbol("_vtc");function fb(e,t,n){const r=e[ub];r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const Su=Symbol("_vod"),db=Symbol("_vsh"),mb=Symbol(""),hb=/(^|;)\s*display\s*:/;function pb(e,t,n){const r=e.style,s=Ge(n);let i=!1;if(n&&!s){if(t)if(Ge(t))for(const o of t.split(";")){const a=o.slice(0,o.indexOf(":")).trim();n[a]==null&&Ui(r,a,"")}else for(const o in t)n[o]==null&&Ui(r,o,"");for(const o in n)o==="display"&&(i=!0),Ui(r,o,n[o])}else if(s){if(t!==n){const o=r[mb];o&&(n+=";"+o),r.cssText=n,i=hb.test(n)}}else t&&e.removeAttribute("style");Su in e&&(e[Su]=i?r.display:"",e[db]&&(r.display="none"))}const Cu=/\s*!important$/;function Ui(e,t,n){if(ce(n))n.forEach(r=>Ui(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=gb(e,t);Cu.test(n)?e.setProperty(rs(r),n.replace(Cu,""),"important"):e[r]=n}}const Nu=["Webkit","Moz","ms"],sa={};function gb(e,t){const n=sa[t];if(n)return n;let r=Xt(t);if(r!=="filter"&&r in e)return sa[t]=r;r=bo(r);for(let s=0;s<Nu.length;s++){const i=Nu[s]+r;if(i in e)return sa[t]=i}return t}const Lu="http://www.w3.org/1999/xlink";function Iu(e,t,n,r,s,i=T_(t)){r&&t.startsWith("xlink:")?n==null?e.removeAttributeNS(Lu,t.slice(6,t.length)):e.setAttributeNS(Lu,t,n):n==null||i&&!bm(n)?e.removeAttribute(t):e.setAttribute(t,i?"":String(n))}function _b(e,t,n,r,s,i,o){if(t==="innerHTML"||t==="textContent"){r&&o(r,s,i),e[t]=n??"";return}const a=e.tagName;if(t==="value"&&a!=="PROGRESS"&&!a.includes("-")){const u=a==="OPTION"?e.getAttribute("value")||"":e.value,c=n==null?"":String(n);(u!==c||!("_value"in e))&&(e.value=c),n==null&&e.removeAttribute(t),e._value=n;return}let l=!1;if(n===""||n==null){const u=typeof e[t];u==="boolean"?n=bm(n):n==null&&u==="string"?(n="",l=!0):u==="number"&&(n=0,l=!0)}try{e[t]=n}catch{}l&&e.removeAttribute(t)}function Cr(e,t,n,r){e.addEventListener(t,n,r)}function vb(e,t,n,r){e.removeEventListener(t,n,r)}const Pu=Symbol("_vei");function bb(e,t,n,r,s=null){const i=e[Pu]||(e[Pu]={}),o=i[t];if(r&&o)o.value=r;else{const[a,l]=yb(t);if(r){const u=i[t]=Ab(r,s);Cr(e,a,u,l)}else o&&(vb(e,a,o,l),i[t]=void 0)}}const Ru=/(?:Once|Passive|Capture)$/;function yb(e){let t;if(Ru.test(e)){t={};let r;for(;r=e.match(Ru);)e=e.slice(0,e.length-r[0].length),t[r[0].toLowerCase()]=!0}return[e[2]===":"?e.slice(3):rs(e.slice(2)),t]}let ia=0;const Eb=Promise.resolve(),wb=()=>ia||(Eb.then(()=>ia=0),ia=Date.now());function Ab(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Mt(Tb(r,n.value),t,5,[r])};return n.value=e,n.attached=wb(),n}function Tb(e,t){if(ce(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>s=>!s._stopped&&r&&r(s))}else return t}const xu=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Ob=(e,t,n,r,s,i,o,a,l)=>{const u=s==="svg";t==="class"?fb(e,r,u):t==="style"?pb(e,n,r):go(t)?jl(t)||bb(e,t,n,r,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Sb(e,t,r,u))?(_b(e,t,r,i,o,a,l),(t==="value"||t==="checked"||t==="selected")&&Iu(e,t,r,u,o,t!=="value")):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Iu(e,t,r,u))};function Sb(e,t,n,r){if(r)return!!(t==="innerHTML"||t==="textContent"||t in e&&xu(t)&&he(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const s=e.tagName;if(s==="IMG"||s==="VIDEO"||s==="CANVAS"||s==="SOURCE")return!1}return xu(t)&&Ge(n)?!1:t in e}const ku=e=>{const t=e.props["onUpdate:modelValue"]||!1;return ce(t)?n=>Di(t,n):t};function Cb(e){e.target.composing=!0}fun Line truncated
* pinia v2.1.7
* (c) 2023 Eduardo San Martin Morote
* @license MIT
*/let ph;const No=e=>ph=e,gh=Symbol();function Xa(e){return e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"&&typeof e.toJSON!="function"}var Ss;(function(e){e.direct="direct",e.patchObject="patch object",e.patchFunction="patch function"})(Ss||(Ss={}));function kb(){const e=Vl(!0),t=e.run(()=>ge({}));let n=[],r=[];const s=ql({install(i){No(s),s._a=i,i.provide(gh,s),i.config.globalProperties.$pinia=s,r.forEach(o=>n.push(o)),r=[]},use(i){return!this._a&&!xb?r.push(i):n.push(i),this},_p:n,_a:null,_e:e,_s:new Map,state:t});return s}const _h=()=>{};function Mu(e,t,n,r=_h){e.push(t);const s=()=>{const i=e.indexOf(t);i>-1&&(e.splice(i,1),r())};return!n&&wm()&&S_(s),s}function Tr(e,...t){e.slice().forEach(n=>{n(...t)})}const $b=e=>e();function Ja(e,t){e instanceof Map&&t instanceof Map&&t.forEach((n,r)=>e.set(r,n)),e instanceof Set&&t instanceof Set&&t.forEach(e.add,e);for(const n in t){if(!t.hasOwnProperty(n))continue;const r=t[n],s=e[n];Xa(s)&&Xa(r)&&e.hasOwnProperty(n)&&!He(r)&&!In(r)?e[n]=Ja(s,r):e[n]=r}return e}const Db=Symbol();function Mb(e){return!Xa(e)||!e.hasOwnProperty(Db)}const{assign:wn}=Object;function Fb(e){return!!(He(e)&&e.effect)}function jb(e,t,n,r){const{state:s,actions:i,getters:o}=t,a=n.state.value[e];let l;function u(){a||(n.state.value[e]=s?s():{});const c=X_(n.state.value[e]);return wn(c,i,Object.keys(o||{}).reduce((f,d)=>(f[d]=ql(ne(()=>{No(n);const m=n._s.get(e);return o[d].call(m,m)})),f),{}))}return l=vh(e,u,t,n,r,!0),l}function vh(e,t,n={},r,s,i){let o;const a=wn({actions:{}},n),l={deep:!0};let u,c,f=[],d=[],m;const p=r.state.value[e];!i&&!p&&(r.state.value[e]={}),ge({});let v;function y($){let P;u=c=!1,typeof $=="function"?($(r.state.value[e]),P={type:Ss.patchFunction,storeId:e,events:m}):(Ja(r.state.value[e],$),P={type:Ss.patchObject,payload:$,storeId:e,events:m});const q=v=Symbol();Ms().then(()=>{v===q&&(u=!0)}),c=!0,Tr(f,P,r.state.value[e])}const w=i?function(){const{state:P}=n,q=P?P():{};this.$patch(ie=>{wn(ie,q)})}:_h;function S(){o.stop(),f=[],d=[],r._s.delete(e)}function E($,P){return function(){No(r);const q=Array.from(arguments),ie=[],Q=[];function le(ee){ie.push(ee)}function je(ee){Q.push(ee)}Tr(d,{args:q,name:$,store:C,after:le,onError:je});let Ce;try{Ce=P.apply(this&&this.$id===e?this:C,q)}catch(ee){throw Tr(Q,ee),ee}return Ce instanceof Promise?Ce.then(ee=>(Tr(ie,ee),ee)).catch(ee=>(Tr(Q,ee),Promise.reject(ee))):(Tr(ie,Ce),Ce)}}const A={_p:r,$id:e,$onAction:Mu.bind(null,d),$patch:y,$reset:w,$subscribe($,P={}){const q=Mu(f,$,P.detached,()=>ie()),ie=o.run(()=>it(()=>r.state.value[e],Q=>{(P.flush==="sync"?c:u)&&$({storeId:e,type:Ss.direct,events:m},Q)},wn({},l,P)));return q},$dispose:S},C=Vn(A);r._s.set(e,C);const I=(r._a&&r._a.runWithContext||$b)(()=>r._e.run(()=>(o=Vl()).run(t)));for(const $ in I){const P=I[$];if(He(P)&&!Fb(P)||In(P))i||(p&&Mb(P)&&(He(P)?P.value=p[$]:Ja(P,p[$])),r.state.value[e][$]=P);else if(typeof P=="function"){const q=E($,P);I[$]=q,a.actions[$]=P}}return wn(C,I),wn(Ae(C),I),Object.defineProperty(C,"$state",{get:()=>r.state.value[e],set:$=>{y(P=>{wn(P,$)})}}),r._p.forEach($=>{wn(C,o.run(()=>$({store:C,app:r._a,pinia:r,options:a})))}),p&&i&&n.hydrate&&n.hydrate(C.$state,p),u=!0,c=!0,C}function Ub(e,t,n){let r,s;const i=typeof t=="function";r=e,s=i?n:t;function o(a,l){const u=Iv();return a=a||(u?st(gh,null):null),a&&No(a),a=ph,a._s.has(r)||(i?vh(r,t,s,a):jb(r,s,a)),a._s.get(r)}return o.$id=r,o}/*!
* shared v9.13.1
* (c) 2024 kazuya kawaguchi
* Released under the MIT License.
*/const to=typeof window<"u",Bn=(e,t=!1)=>t?Symbol.for(e):Symbol(e),Hb=(e,t,n)=>Vb({l:e,k:t,s:n}),Vb=e=>JSON.stringify(e).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/\u0027/g,"\\u0027"),Ke=e=>typeof e=="number"&&isFinite(e),Bb=e=>yh(e)==="[object Date]",xn=e=>yh(e)==="[object RegExp]",Lo=e=>fe(e)&&Object.keys(e).length===0,tt=Object.assign;let Fu;const rn=()=>Fu||(Fu=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function ju(e){return e.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}const Wb=Object.prototype.hasOwnProperty;function no(e,t){return Wb.call(e,t)}const De=Array.isArray,Re=e=>typeof e=="function",G=e=>typeof e=="string",ve=e=>typeof e=="boolean",Se=e=>e!==null&&typeof e=="object",Yb=e=>Se(e)&&Re(e.then)&&Re(e.catch),bh=Object.prototype.toString,yh=e=>bh.call(e),fe=e=>{if(!Se(e))return!1;const t=Object.getPrototypeOf(e);return t===null||t.constructor===Object},Kb=e=>e==null?"":De(e)||fe(e)&&e.toString===bh?JSON.stringify(e,null,2):String(e);function zb(e,t=""){return e.reduce((n,r,s)=>s===0?n+r:n+t+r,"")}function Io(e){let t=e;return()=>++t}function Gb(e,t){typeof console<"u"&&(console.warn("[intlify] "+e),t&&console.warn(t.stack))}const bi=e=>!Se(e)||De(e);function Hi(e,t){if(bi(e)||bi(t))throw new Error("Invalid value");const n=[{src:e,des:t}];for(;n.length;){const{src:r,des:s}=n.pop();Object.keys(r).forEach(i=>{bi(r[i])||bi(s[i])?s[i]=r[i]:n.push({src:r[i],des:s[i]})})}}/*!
* message-compiler v9.13.1
* (c) 2024 kazuya kawaguchi
* Released under the MIT License.
*/function qb(e,t,n){return{line:e,column:t,offset:n}}function ro(e,t,n){return{start:e,end:t}}const Xb=/\{([0-9a-zA-Z]+)\}/g;function Eh(e,...t){return t.length===1&&Jb(t[0])&&(t=t[0]),(!t||!t.hasOwnProperty)&&(t={}),e.replace(Xb,(n,r)=>t.hasOwnProperty(r)?t[r]:"")}const wh=Object.assign,Uu=e=>typeof e=="string",Jb=e=>e!==null&&typeof e=="object";function Ah(e,t=""){return e.reduce((n,r,s)=>s===0?n+r:n+t+r,"")}const oc={USE_MODULO_SYNTAX:1,__EXTEND_POINT__:2},Qb={[oc.USE_MODULO_SYNTAX]:"Use modulo before '{{0}}'."};function Zb(e,t,...n){const r=Eh(Qb[e],...n||[]),s={message:String(r),code:e};return t&&(s.location=t),s}const oe={EXPECTED_TOKEN:1,INVALID_TOKEN_IN_PLACEHOLDER:2,UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER:3,UNKNOWN_ESCAPE_SEQUENCE:4,INVALID_UNICODE_ESCAPE_SEQUENCE:5,UNBALANCED_CLOSING_BRACE:6,UNTERMINATED_CLOSING_BRACE:7,EMPTY_PLACEHOLDER:8,NOT_ALLOW_NEST_PLACEHOLDER:9,INVALID_LINKED_FORMAT:10,MUST_HAVE_MESSAGES_IN_PLURAL:11,UNEXPECTED_EMPTY_LINKED_MODIFIER:12,UNEXPECTED_EMPTY_LINKED_KEY:13,UNEXPECTED_LEXICAL_ANALYSIS:14,UNHANDLED_CODEGEN_NODE_TYPE:15,UNHANDLED_MINIFIER_NODE_TYPE:16,__EXTEND_POINT__:17},ey={[oe.EXPECTED_TOKEN]:"Expected token: '{0}'",[oe.INVALID_TOKEN_IN_PLACEHOLDER]:"Invalid token in placeholder: '{0}'",[oe.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]:"Unterminated single quote in placeholder",[oe.UNKNOWN_ESCAPE_SEQUENCE]:"Unknown escape sequence: \\{0}",[oe.INVALID_UNICODE_ESCAPE_SEQUENCE]:"Invalid unicode escape sequence: {0}",[oe.UNBALANCED_CLOSING_BRACE]:"Unbalanced closing brace",[oe.UNTERMINATED_CLOSING_BRACE]:"Unterminated closing brace",[oe.EMPTY_PLACEHOLDER]:"Empty placeholder",[oe.NOT_ALLOW_NEST_PLACEHOLDER]:"Not allowed nest placeholder",[oe.INVALID_LINKED_FORMAT]:"Invalid linked format",[oe.MUST_HAVE_MESSAGES_IN_PLURAL]:"Plural must have messages",[oe.UNEXPECTED_EMPTY_LINKED_MODIFIER]:"Unexpected empty linked modifier",[oe.UNEXPECTED_EMPTY_LINKED_KEY]:"Unexpected empty linked key",[oe.UNEXPECTED_LEXICAL_ANALYSIS]:"Unexpected lexical analysis in token: '{0}'",[oe.UNHANDLED_CODEGEN_NODE_TYPE]:"unhandled codegen node type: '{0}'",[oe.UNHANDLED_MINIFIER_NODE_TYPE]:"unhandled mimifier node type: '{0}'"};function is(e,t,n={}){const{domain:r,messages:s,args:i}=n,o=Eh((s||ey)[e]||"",...i||[]),a=new SyntaxError(String(o));return a.code=e,t&&(a.location=t),a.domain=r,a}function ty(e){throw e}const Zt=" ",ny="\r",at=`
`,ry="\u2028",sy="\u2029";function iy(e){const t=e;let n=0,r=1,s=1,i=0;const o=I=>t[I]===ny&&t[I+1]===at,a=I=>t[I]===at,l=I=>t[I]===sy,u=I=>t[I]===ry,c=I=>o(I)||a(I)||l(I)||u(I),f=()=>n,d=()=>r,m=()=>s,p=()=>i,v=I=>o(I)||l(I)||u(I)?at:t[I],y=()=>v(n),w=()=>v(n+i);function S(){return i=0,c(n)&&(r++,s=0),o(n)&&n++,n++,s++,t[n]}function E(){return o(n+i)&&i++,i++,t[n+i]}function A(){n=0,r=1,s=1,i=0}function C(I=0){i=I}function O(){const I=n+i;for(;I!==n;)S();i=0}return{index:f,line:d,column:m,peekOffset:p,charAt:v,currentChar:y,currentPeek:w,next:S,peek:E,reset:A,resetPeek:C,skipToPeek:O}}const _n=void 0,oy=".",Hu="'",ay="tokenizer";function ly(e,t={}){const n=t.location!==!1,r=iy(e),s=()=>r.index(),i=()=>qb(r.line(),r.column(),r.index()),o=i(),a=s(),l={currentType:14,offset:a,startLoc:o,endLoc:o,lastType:14,lastOffset:a,lastStartLoc:o,lastEndLoc:o,braceNest:0,inLinked:!1,text:""},u=()=>l,{onError:c}=t;function f(h,_,T,...M){const K=u();if(_.column+=T,_.offset+=T,c){const U=n?ro(K.startLoc,_):null,L=is(h,U,{domain:ay,args:M});c(L)}}function d(h,_,T){h.endLoc=i(),h.currentType=_;const M={type:_};return n&&(M.loc=ro(h.startLoc,h.endLoc)),T!=null&&(M.value=T),M}const m=h=>d(h,14);function p(h,_){return h.currentChar()===_?(h.next(),_):(f(oe.EXPECTED_TOKEN,i(),0,_),"")}function v(h){let _="";for(;h.currentPeek()===Zt||h.currentPeek()===at;)_+=h.currentPeek(),h.peek();return _}function y(h){const _=v(h);return h.skipToPeek(),_}function w(h){if(h===_n)return!1;const _=h.charCodeAt(0);return _>=97&&_<=122||_>=65&&_<=90||_===95}function S(h){if(h===_n)return!1;const _=h.charCodeAt(0);return _>=48&&_<=57}function E(h,_){const{currentType:T}=_;if(T!==2)return!1;v(h);const M=w(h.currentPeek());return h.resetPeek(),M}function A(h,_){const{currentType:T}=_;if(T!==2)return!1;v(h);const M=h.currentPeek()==="-"?h.peek():h.currentPeek(),K=S(M);return h.resetPeek(),K}function C(h,_){const{currentType:T}=_;if(T!==2)return!1;v(h);const M=h.currentPeek()===Hu;return h.resetPeek(),M}function O(h,_){const{currentType:T}=_;if(T!==8)return!1;v(h);const M=h.currentPeek()===".";return h.resetPeek(),M}function I(h,_){const{currentType:T}=_;if(T!==9)return!1;v(h);const M=w(h.currentPeek());return h.resetPeek(),M}function $(h,_){const{currentType:T}=_;if(!(T===8||T===12))return!1;v(h);const M=h.currentPeek()===":";return h.resetPeek(),M}function P(h,_){const{currentType:T}=_;if(T!==10)return!1;const M=()=>{const U=h.currentPeek();return U==="{"?w(h.peek()):U==="@"||U==="%"||U==="|"||U===":"||U==="."||U===Zt||!U?!1:U===at?(h.peek(),M()):Q(h,!1)},K=M();return h.resetPeek(),K}function q(h){v(h);const _=h.currentPeek()==="|";return h.resetPeek(),_}function ie(h){const _=v(h),T=h.currentPeek()==="%"&&h.peek()==="{";return h.resetPeek(),{isModulo:T,hasSpace:_.length>0}}function Q(h,_=!0){const T=(K=!1,U="",L=!1)=>{const R=h.currentPeek();return R==="{"?U==="%"?!1:K:R==="@"||!R?U==="%"?!0:K:R==="%"?(h.peek(),T(K,"%",!0)):R==="|"?U==="%"||L?!0:!(U===Zt||U===at):R===Zt?(h.peek(),T(!0,Zt,L)):R===at?(h.peek(),T(!0,at,L)):!0},M=T();return _&&h.resetPeek(),M}function le(h,_){const T=h.currentChar();return T===_n?_n:_(T)?(h.next(),T):null}function je(h){const _=h.charCodeAt(0);return _>=97&&_<=122||_>=65&&_<=90||_>=48&&_<=57||_===95||_===36}function Ce(h){return le(h,je)}function ee(h){const _=h.charCodeAt(0);return _>=97&&_<=122||_>=65&&_<=90||_>=48&&_<=57||_===95||_===36||_===45}function ae(h){return le(h,ee)}function de(h){const _=h.charCodeAt(0);return _>=48&&_<=57}function xe(h){return le(h,de)}function pe(h){const _=h.charCodeAt(0);return _>=48&&_<=57||_>=65&&_<=70||_>=97&&_<=102}function Ee(h){return le(h,pe)}function be(h){let _="",T="";for(;_=xe(h);)T+=_;return T}function et(h){y(h);const _=h.currentChar();return _!=="%"&&f(oe.EXPECTED_TOKEN,i(),0,_),h.next(),"%"}function Be(h){let _="";for(;;){const T=h.currentChar();if(T==="{"||T==="}"||T==="@"||T==="|"||!T)break;if(T==="%")if(Q(h))_+=T,h.next();else break;else if(T===Zt||T===at)if(Q(h))_+=T,h.next();else{if(q(h))break;_+=T,h.next()}else _+=T,h.next()}return _}function We(h){y(h);let _="",T="";for(;_=ae(h);)T+=_;return h.currentChar()===_n&&f(oe.UNTERMINATED_CLOSING_BRACE,i(),0),T}function Le(h){y(h);let _="";return h.currentChar()==="-"?(h.next(),_+=`-${be(h)}`):_+=be(h),h.currentChar()===_n&&f(oe.UNTERMINATED_CLOSING_BRACE,i(),0),_}function F(h){return h!==Hu&&h!==at}function Y(h){y(h),p(h,"'");let _="",T="";for(;_=le(h,F);)_==="\\"?T+=W(h):T+=_;const M=h.currentChar();return M===at||M===_n?(f(oe.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER,i(),0),M===at&&(h.next(),p(h,"'")),T):(p(h,"'"),T)}function W(h){const _=h.currentChar();switch(_){case"\\":case"'":return h.next(),`\\${_}`;case"u":return J(h,_,4);case"U":return J(h,_,6);default:return f(oe.UNKNOWN_ESCAPE_SEQUENCE,i(),0,_),""}}function J(h,_,T){p(h,_);let M="";for(let K=0;K<T;K++){const U=Ee(h);if(!U){f(oe.INVALID_UNICODE_ESCAPE_SEQUENCE,i(),0,`\\${_}${M}${h.currentChar()}`);break}M+=U}return`\\${_}${M}`}function _e(h){return h!=="{"&&h!= Line truncated
`,o=t.needIndent?t.needIndent:n!=="arrow",a=e.helpers||[],l=vy(e,{mode:n,filename:r,sourceMap:s,breakLineCode:i,needIndent:o});l.push(n==="normal"?"function __msg__ (ctx) {":"(ctx) => {"),l.indent(o),a.length>0&&(l.push(`const { ${Ah(a.map(f=>`${f}: _${f}`),", ")} } = ctx`),l.newline()),l.push("return "),Yr(l,e),l.deindent(o),l.push("}"),delete e.helpers;const{code:u,map:c}=l.context();return{ast:e,code:u,map:c?c.toJSON():void 0}};function Ty(e,t={}){const n=wh({},t),r=!!n.jit,s=!!n.minify,i=n.optimize==null?!0:n.optimize,a=dy(n).parse(e);return r?(i&&py(a),s&&Nr(a),{ast:a,code:""}):(hy(a,n),Ay(a,n))}/*!
* core-base v9.13.1
* (c) 2024 kazuya kawaguchi
* Released under the MIT License.
*/function Oy(){typeof __INTLIFY_PROD_DEVTOOLS__!="boolean"&&(rn().__INTLIFY_PROD_DEVTOOLS__=!1),typeof __INTLIFY_JIT_COMPILATION__!="boolean"&&(rn().__INTLIFY_JIT_COMPILATION__=!1),typeof __INTLIFY_DROP_MESSAGE_COMPILER__!="boolean"&&(rn().__INTLIFY_DROP_MESSAGE_COMPILER__=!1)}const Wn=[];Wn[0]={w:[0],i:[3,0],"[":[4],o:[7]};Wn[1]={w:[1],".":[2],"[":[4],o:[7]};Wn[2]={w:[2],i:[3,0],0:[3,0]};Wn[3]={i:[3,0],0:[3,0],w:[1,1],".":[2,1],"[":[4,1],o:[7,1]};Wn[4]={"'":[5,0],'"':[6,0],"[":[4,2],"]":[1,3],o:8,l:[4,0]};Wn[5]={"'":[4,0],o:8,l:[5,0]};Wn[6]={'"':[4,0],o:8,l:[6,0]};const Sy=/^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;function Cy(e){return Sy.test(e)}function Ny(e){const t=e.charCodeAt(0),n=e.charCodeAt(e.length-1);return t===n&&(t===34||t===39)?e.slice(1,-1):e}function Ly(e){if(e==null)return"o";switch(e.charCodeAt(0)){case 91:case 93:case 46:case 34:case 39:return e;case 95:case 36:case 45:return"i";case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"w"}return"i"}function Iy(e){const t=e.trim();return e.charAt(0)==="0"&&isNaN(parseInt(e))?!1:Cy(t)?Ny(t):"*"+t}function Py(e){const t=[];let n=-1,r=0,s=0,i,o,a,l,u,c,f;const d=[];d[0]=()=>{o===void 0?o=a:o+=a},d[1]=()=>{o!==void 0&&(t.push(o),o=void 0)},d[2]=()=>{d[0](),s++},d[3]=()=>{if(s>0)s--,r=4,d[0]();else{if(s=0,o===void 0||(o=Iy(o),o===!1))return!1;d[1]()}};function m(){const p=e[n+1];if(r===5&&p==="'"||r===6&&p==='"')return n++,a="\\"+p,d[0](),!0}for(;r!==null;)if(n++,i=e[n],!(i==="\\"&&m())){if(l=Ly(i),f=Wn[r],u=f[l]||f.l||8,u===8||(r=u[0],u[1]!==void 0&&(c=d[u[1]],c&&(a=i,c()===!1))))return;if(r===7)return t}}const Wu=new Map;function Ry(e,t){return Se(e)?e[t]:null}function xy(e,t){if(!Se(e))return null;let n=Wu.get(t);if(n||(n=Py(t),n&&Wu.set(t,n)),!n)return null;const r=n.length;let s=e,i=0;for(;i<r;){const o=s[n[i]];if(o===void 0||Re(s))return null;s=o,i++}return s}const ky=e=>e,$y=e=>"",Dy="text",My=e=>e.length===0?"":zb(e),Fy=Kb;function Yu(e,t){return e=Math.abs(e),t===2?e?e>1?1:0:1:e?Math.min(e,2):0}function jy(e){const t=Ke(e.pluralIndex)?e.pluralIndex:-1;return e.named&&(Ke(e.named.count)||Ke(e.named.n))?Ke(e.named.count)?e.named.count:Ke(e.named.n)?e.named.n:t:t}function Uy(e,t){t.count||(t.count=e),t.n||(t.n=e)}function Hy(e={}){const t=e.locale,n=jy(e),r=Se(e.pluralRules)&&G(t)&&Re(e.pluralRules[t])?e.pluralRules[t]:Yu,s=Se(e.pluralRules)&&G(t)&&Re(e.pluralRules[t])?Yu:void 0,i=w=>w[r(n,w.length,s)],o=e.list||[],a=w=>o[w],l=e.named||{};Ke(e.pluralIndex)&&Uy(n,l);const u=w=>l[w];function c(w){const S=Re(e.messages)?e.messages(w):Se(e.messages)?e.messages[w]:!1;return S||(e.parent?e.parent.message(w):$y)}const f=w=>e.modifiers?e.modifiers[w]:ky,d=fe(e.processor)&&Re(e.processor.normalize)?e.processor.normalize:My,m=fe(e.processor)&&Re(e.processor.interpolate)?e.processor.interpolate:Fy,p=fe(e.processor)&&G(e.processor.type)?e.processor.type:Dy,y={list:a,named:u,plural:i,linked:(w,...S)=>{const[E,A]=S;let C="text",O="";S.length===1?Se(E)?(O=E.modifier||O,C=E.type||C):G(E)&&(O=E||O):S.length===2&&(G(E)&&(O=E||O),G(A)&&(C=A||C));const I=c(w)(y),$=C==="vnode"&&De(I)&&O?I[0]:I;return O?f(O)($,C):$},message:c,type:p,interpolate:m,normalize:d,values:tt({},o,l)};return y}let Us=null;function Vy(e){Us=e}function By(e,t,n){Us&&Us.emit("i18n:init",{timestamp:Date.now(),i18n:e,version:t,meta:n})}const Wy=Yy("function:translate");function Yy(e){return t=>Us&&Us.emit(e,t)}const Th=oc.__EXTEND_POINT__,Xn=Io(Th),Ky={NOT_FOUND_KEY:Th,FALLBACK_TO_TRANSLATE:Xn(),CANNOT_FORMAT_NUMBER:Xn(),FALLBACK_TO_NUMBER_FORMAT:Xn(),CANNOT_FORMAT_DATE:Xn(),FALLBACK_TO_DATE_FORMAT:Xn(),EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER:Xn(),__EXTEND_POINT__:Xn()},Oh=oe.__EXTEND_POINT__,Jn=Io(Oh),$t={INVALID_ARGUMENT:Oh,INVALID_DATE_ARGUMENT:Jn(),INVALID_ISO_DATE_ARGUMENT:Jn(),NOT_SUPPORT_NON_STRING_MESSAGE:Jn(),NOT_SUPPORT_LOCALE_PROMISE_VALUE:Jn(),NOT_SUPPORT_LOCALE_ASYNC_FUNCTION:Jn(),NOT_SUPPORT_LOCALE_TYPE:Jn(),__EXTEND_POINT__:Jn()};function Kt(e){return is(e,null,void 0)}function lc(e,t){return t.locale!=null?Ku(t.locale):Ku(e.locale)}let aa;function Ku(e){if(G(e))return e;if(Re(e)){if(e.resolvedOnce&&aa!=null)return aa;if(e.constructor.name==="Function"){const t=e();if(Yb(t))throw Kt($t.NOT_SUPPORT_LOCALE_PROMISE_VALUE);return aa=t}else throw Kt($t.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION)}else throw Kt($t.NOT_SUPPORT_LOCALE_TYPE)}function zy(e,t,n){return[...new Set([n,...De(t)?t:Se(t)?Object.keys(t):G(t)?[t]:[n]])]}function Sh(e,t,n){const r=G(n)?n:Kr,s=e;s.__localeChainCache||(s.__localeChainCache=new Map);let i=s.__localeChainCache.get(r);if(!i){i=[];let o=[n];for(;De(o);)o=zu(i,o,t);const a=De(t)||!fe(t)?t:t.default?t.default:null;o=G(a)?[a]:a,De(o)&&zu(i,o,!1),s.__localeChainCache.set(r,i)}return i}function zu(e,t,n){let r=!0;for(let s=0;s<t.length&&ve(r);s++){const i=t[s];G(i)&&(r=Gy(e,t[s],n))}return r}function Gy(e,t,n){let r;const s=t.split("-");do{const i=s.join("-");r=qy(e,i,n),s.splice(-1,1)}while(s.length&&r===!0);return r}function qy(e,t,n){let rLine truncated
* vue-i18n v9.13.1
* (c) 2024 kazuya kawaguchi
* Released under the MIT License.
*/const mE="9.13.1";function hE(){typeof __VUE_I18N_FULL_INSTALL__!="boolean"&&(rn().__VUE_I18N_FULL_INSTALL__=!0),typeof __VUE_I18N_LEGACY_API__!="boolean"&&(rn().__VUE_I18N_LEGACY_API__=!0),typeof __INTLIFY_JIT_COMPILATION__!="boolean"&&(rn().__INTLIFY_JIT_COMPILATION__=!1),typeof __INTLIFY_DROP_MESSAGE_COMPILER__!="boolean"&&(rn().__INTLIFY_DROP_MESSAGE_COMPILER__=!1),typeof __INTLIFY_PROD_DEVTOOLS__!="boolean"&&(rn().__INTLIFY_PROD_DEVTOOLS__=!1)}const Fh=Ky.__EXTEND_POINT__,en=Io(Fh);en(),en(),en(),en(),en(),en(),en(),en(),en();const jh=$t.__EXTEND_POINT__,dt=Io(jh),ze={UNEXPECTED_RETURN_TYPE:jh,INVALID_ARGUMENT:dt(),MUST_BE_CALL_SETUP_TOP:dt(),NOT_INSTALLED:dt(),NOT_AVAILABLE_IN_LEGACY_MODE:dt(),REQUIRED_VALUE:dt(),INVALID_VALUE:dt(),CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN:dt(),NOT_INSTALLED_WITH_PROVIDE:dt(),UNEXPECTED_ERROR:dt(),NOT_COMPATIBLE_LEGACY_VUE_I18N:dt(),BRIDGE_SUPPORT_VUE_2_ONLY:dt(),MUST_DEFINE_I18N_OPTION_IN_ALLOW_COMPOSITION:dt(),NOT_AVAILABLE_COMPOSITION_IN_LEGACY:dt(),__EXTEND_POINT__:dt()};function Qe(e,...t){return is(e,null,void 0)}const nl=Bn("__translateVNode"),rl=Bn("__datetimeParts"),sl=Bn("__numberParts"),Uh=Bn("__setPluralRules"),Hh=Bn("__injectWithOption"),il=Bn("__dispose");function Hs(e){if(!Se(e))return e;for(const t in e)if(no(e,t))if(!t.includes("."))Se(e[t])&&Hs(e[t]);else{const n=t.split("."),r=n.length-1;let s=e,i=!1;for(let o=0;o<r;o++){if(n[o]in s||(s[n[o]]={}),!Se(s[n[o]])){i=!0;break}s=s[n[o]]}i||(s[n[r]]=e[t],delete e[t]),Se(s[n[r]])&&Hs(s[n[r]])}return e}function Ro(e,t){const{messages:n,__i18n:r,messageResolver:s,flatJson:i}=t,o=fe(n)?n:De(r)?{}:{[e]:{}};if(De(r)&&r.forEach(a=>{if("locale"in a&&"resource"in a){const{locale:l,resource:u}=a;l?(o[l]=o[l]||{},Hi(u,o[l])):Hi(u,o)}else G(a)&&Hi(JSON.parse(a),o)}),s==null&&i)for(const a in o)no(o,a)&&Hs(o[a]);return o}function Vh(e){return e.type}function Bh(e,t,n){let r=Se(t.messages)?t.messages:{};"__i18nGlobal"in n&&(r=Ro(e.locale.value,{messages:r,__i18n:n.__i18nGlobal}));const s=Object.keys(r);s.length&&s.forEach(i=>{e.mergeLocaleMessage(i,r[i])});{if(Se(t.datetimeFormats)){const i=Object.keys(t.datetimeFormats);i.length&&i.forEach(o=>{e.mergeDateTimeFormat(o,t.datetimeFormats[o])})}if(Se(t.numberFormats)){const i=Object.keys(t.numberFormats);i.length&&i.forEach(o=>{e.mergeNumberFormat(o,t.numberFormats[o])})}}}function af(e){return ye(Js,null,e,0)}const lf="__INTLIFY_META__",cf=()=>[],pE=()=>!1;let uf=0;function ff(e){return(t,n,r,s)=>e(n,r,Wr()||void 0,s)}const gE=()=>{const e=Wr();let t=null;return e&&(t=Vh(e)[lf])?{[lf]:t}:null};function uc(e={},t){const{__root:n,__injectWithOption:r}=e,s=n===void 0,i=e.flatJson,o=to?ge:Jl,a=!!e.translateExistCompatible;let l=ve(e.inheritLocale)?e.inheritLocale:!0;const u=o(n&&l?n.locale.value:G(e.locale)?e.locale:Kr),c=o(n&&l?n.fallbackLocale.value:G(e.fallbackLocale)||De(e.fallbackLocale)||fe(e.fallbackLocale)||e.fallbackLocale===!1?e.fallbackLocale:u.value),f=o(Ro(u.value,e)),d=o(fe(e.datetimeFormats)?e.datetimeFormats:{[u.value]:{}}),m=o(fe(e.numberFormats)?e.numberFormats:{[u.value]:{}});let p=n?n.missingWarn:ve(e.missingWarn)||xn(e.missingWarn)?e.missingWarn:!0,v=n?n.fallbackWarn:ve(e.fallbackWarn)||xn(e.fallbackWarn)?e.fallbackWarn:!0,y=n?n.fallbackRoot:ve(e.fallbackRoot)?e.fallbackRoot:!0,w=!!e.fallbackFormat,S=Re(e.missing)?e.missing:null,E=Re(e.missing)?ff(e.missing):null,A=Re(e.postTranslation)?e.postTranslation:null,C=n?n.warnHtmlMessage:ve(e.warnHtmlMessage)?e.warnHtmlMessage:!0,O=!!e.escapeParameter;const I=n?n.modifiers:fe(e.modifiers)?e.modifiers:{};let $=e.pluralRules||n&&n.pluralRules,P;P=(()=>{s&&Ju(null);const L={version:mE,locale:u.value,fallbackLocale:c.value,messages:f.value,modifiers:I,pluralRules:$,missing:E===null?void 0:E,missingWarn:p,fallbackWarn:v,fallbackFormat:w,unresolving:!0,postTranslation:A===null?void 0:A,warnHtmlMessage:C,escapeParameter:O,messageResolver:e.messageResolver,messageCompiler:e.messageCompiler,__meta:{framework:"vue"}};L.datetimeFormats=d.value,L.numberFormats=m.value,L.__datetimeFormatters=fe(P)?P.__datetimeFormatters:void 0,L.__numberFormatters=fe(P)?P.__numberFormatters:void 0;const R=rE(L);return s&&Ju(R),R})(),hs(P,u.value,c.value);function ie(){return[u.value,c.value,f.value,d.value,m.value]}const Q=ne({get:()=>u.value,set:L=>{u.value=L,P.locale=u.value}}),le=ne({get:()=>c.value,set:L=>{c.value=L,P.fallbackLocale=c.value,hs(P,u.value,L)}}),je=ne(()=>f.value),Ce=ne(()=>d.value),ee=ne(()=>m.value);function ae(){return Re(A)?A:null}function de(L){A=L,P.postTranslation=L}function xe(){return S}function pe(L){L!==null&&(E=ff(L)),S=L,P.missing=E}const Ee=(L,R,te,se,Pe,nt)=>{ie();let vt;try{__INTLIFY_PROD_DEVTOOLS__,s||(P.fallbackContext=n?nE():void 0),vt=L(P)}finally{__INTLIFY_PROD_DEVTOOLS__,s||(P.fallbackContext=void 0)}if(te!=="translate exists"&&Ke(vt)&&vt===Po||te==="translate exists"&&!vt){const[di,Ar]=R();return n&&y?se(n):Pe(di)}else{if(nt(vt))return vt;throw Qe(ze.UNEXPECTED_RETURN_TYPE)}};function be(...L){return Ee(RLine truncated
* vue-router v4.3.3
* (c) 2024 Eduardo San Martin Morote
* @license MIT
*/const Lr=typeof document<"u";function jE(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const Ne=Object.assign;function ca(e,t){const n={};for(const r in t){const s=t[r];n[r]=jt(s)?s.map(e):e(s)}return n}const Cs=()=>{},jt=Array.isArray,Kh=/#/g,UE=/&/g,HE=/\//g,VE=/=/g,BE=/\?/g,zh=/\+/g,WE=/%5B/g,YE=/%5D/g,Gh=/%5E/g,KE=/%60/g,qh=/%7B/g,zE=/%7C/g,Xh=/%7D/g,GE=/%20/g;function dc(e){return encodeURI(""+e).replace(zE,"|").replace(WE,"[").replace(YE,"]")}function qE(e){return dc(e).replace(qh,"{").replace(Xh,"}").replace(Gh,"^")}function al(e){return dc(e).replace(zh,"%2B").replace(GE,"+").replace(Kh,"%23").replace(UE,"%26").replace(KE,"`").replace(qh,"{").replace(Xh,"}").replace(Gh,"^")}function XE(e){return al(e).replace(VE,"%3D")}function JE(e){return dc(e).replace(Kh,"%23").replace(BE,"%3F")}function QE(e){return e==null?"":JE(e).replace(HE,"%2F")}function Vs(e){try{return decodeURIComponent(""+e)}catch{}return""+e}const ZE=/\/$/,e1=e=>e.replace(ZE,"");function ua(e,t,n="/"){let r,s={},i="",o="";const a=t.indexOf("#");let l=t.indexOf("?");return a<l&&a>=0&&(l=-1),l>-1&&(r=t.slice(0,l),i=t.slice(l+1,a>-1?a:t.length),s=e(i)),a>-1&&(r=r||t.slice(0,a),o=t.slice(a,t.length)),r=s1(r??t,n),{fullPath:r+(i&&"?")+i+o,path:r,query:s,hash:Vs(o)}}function t1(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function bf(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function n1(e,t,n){const r=t.matched.length-1,s=n.matched.length-1;return r>-1&&r===s&&Gr(t.matched[r],n.matched[s])&&Jh(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function Gr(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Jh(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!r1(e[n],t[n]))return!1;return!0}function r1(e,t){return jt(e)?yf(e,t):jt(t)?yf(t,e):e===t}function yf(e,t){return jt(t)?e.length===t.length&&e.every((n,r)=>n===t[r]):e.length===1&&e[0]===t}function s1(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/"),s=r[r.length-1];(s===".."||s===".")&&r.push("");let i=n.length-1,o,a;for(o=0;o<r.length;o++)if(a=r[o],a!==".")if(a==="..")i>1&&i--;else break;return n.slice(0,i).join("/")+"/"+r.slice(o).join("/")}var Bs;(function(e){e.pop="pop",e.push="push"})(Bs||(Bs={}));var Ns;(function(e){e.back="back",e.forward="forward",e.unknown=""})(Ns||(Ns={}));function i1(e){if(!e)if(Lr){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),e1(e)}const o1=/^[^#]+#/;function a1(e,t){return e.replace(o1,"#")+t}function l1(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}const xo=()=>({left:window.scrollX,top:window.scrollY});function c1(e){let t;if("el"in e){const n=e.el,r=typeof n=="string"&&n.startsWith("#"),s=typeof n=="string"?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!s)return;t=l1(s,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.scrollX,t.top!=null?t.top:window.scrollY)}function Ef(e,t){return(history.state?history.state.position-t:-1)+e}const ll=new Map;function u1(e,t){ll.set(e,t)}function f1(e){const t=ll.get(e);return ll.delete(e),t}let d1=()=>location.protocol+"//"+location.host;function Qh(e,t){const{pathname:n,search:r,hash:s}=t,i=e.indexOf("#");if(i>-1){let a=s.includes(e.slice(i))?e.slice(i).length:1,l=s.slice(a);return l[0]!=="/"&&(l="/"+l),bf(l,"")}return bf(n,e)+r+s}function m1(e,t,n,r){let s=[],i=[],o=null;const a=({state:d})=>{const m=Qh(e,location),p=n.value,v=t.value;let y=0;if(d){if(n.value=m,t.value=d,o&&o===p){o=null;return}y=v?d.position-v.position:0}else r(m);s.forEach(w=>{w(n.value,p,{delta:y,type:Bs.pop,direction:y?y>0?Ns.forward:Ns.back:Ns.unknown})})};function l(){o=n.value}function u(d){s.push(d);const m=()=>{const p=s.indexOf(d);p>-1&&s.splice(p,1)};return i.push(m),m}function c(){const{history:d}=window;d.state&&d.replaceState(Ne({},d.state,{scroll:xo()}),"")}function f(){for(const d of i)d();i=[],window.removeEventListener("popstate",a),window.removeEventListener("beforeunload",c)}return window.addEventListener("popstate",a),window.addEventListener("beforeunload",c,{passive:!0}),{pauseListeners:l,listen:u,destroy:f}}function wf(e,t,n,r=!1,s=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:s?xo():null}}function h1(e){const{history:t,location:n}=window,r={value:Qh(e,n)},s={value:t.state};s.value||i(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(l,u,c){const f=e.indexOf("#"),d=f>-1?(n.host&&document.querySelector("base")?e:e.slice(f))+l:d1()+e+l;try{t[c?"replaceState":"pushState"](u,"",d),s.value=u}catch(m){console.error(m),n[c?"replace":"assignLine truncated
* Bootstrap v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/const bn=new Map,ma={set(e,t,n){bn.has(e)||bn.set(e,new Map);const r=bn.get(e);if(!r.has(t)&&r.size!==0){console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(r.keys())[0]}.`);return}r.set(t,n)},get(e,t){return bn.has(e)&&bn.get(e).get(t)||null},remove(e,t){if(!bn.has(e))return;const n=bn.get(e);n.delete(t),n.size===0&&bn.delete(e)}},sw=1e6,iw=1e3,ml="transitionend",Lp=e=>(e&&window.CSS&&window.CSS.escape&&(e=e.replace(/#([^\s"#']+)/g,(t,n)=>`#${CSS.escape(n)}`)),e),ow=e=>e==null?`${e}`:Object.prototype.toString.call(e).match(/\s([a-z]+)/i)[1].toLowerCase(),aw=e=>{do e+=Math.floor(Math.random()*sw);while(document.getElementById(e));return e},lw=e=>{if(!e)return 0;let{transitionDuration:t,transitionDelay:n}=window.getComputedStyle(e);const r=Number.parseFloat(t),s=Number.parseFloat(n);return!r&&!s?0:(t=t.split(",")[0],n=n.split(",")[0],(Number.parseFloat(t)+Number.parseFloat(n))*iw)},Ip=e=>{e.dispatchEvent(new Event(ml))},an=e=>!e||typeof e!="object"?!1:(typeof e.jquery<"u"&&(e=e[0]),typeof e.nodeType<"u"),kn=e=>an(e)?e.jquery?e[0]:e:typeof e=="string"&&e.length>0?document.querySelector(Lp(e)):null,as=e=>{if(!an(e)||e.getClientRects().length===0)return!1;const t=getComputedStyle(e).getPropertyValue("visibility")==="visible",n=e.closest("details:not([open])");if(!n)return t;if(n!==e){const r=e.closest("summary");if(r&&r.parentNode!==n||r===null)return!1}return t},$n=e=>!e||e.nodeType!==Node.ELEMENT_NODE||e.classList.contains("disabled")?!0:typeof e.disabled<"u"?e.disabled:e.hasAttribute("disabled")&&e.getAttribute("disabled")!=="false",Pp=e=>{if(!document.documentElement.attachShadow)return null;if(typeof e.getRootNode=="function"){const t=e.getRootNode();return t instanceof ShadowRoot?t:null}return e instanceof ShadowRoot?e:e.parentNode?Pp(e.parentNode):null},io=()=>{},ti=e=>{e.offsetHeight},Rp=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,ha=[],cw=e=>{document.readyState==="loading"?(ha.length||document.addEventListener("DOMContentLoaded",()=>{for(const t of ha)t()}),ha.push(e)):e()},It=()=>document.documentElement.dir==="rtl",Rt=e=>{cw(()=>{const t=Rp();if(t){const n=e.NAME,r=t.fn[n];t.fn[n]=e.jQueryInterface,t.fn[n].Constructor=e,t.fn[n].noConflict=()=>(t.fn[n]=r,e.jQueryInterface)}})},pt=(e,t=[],n=e)=>typeof e=="function"?e(...t):n,xp=(e,t,n=!0)=>{if(!n){pt(e);return}const s=lw(t)+5;let i=!1;const o=({target:a})=>{a===t&&(i=!0,t.removeEventListener(ml,o),pt(e))};t.addEventListener(ml,o),setTimeout(()=>{i||Ip(t)},s)},Nc=(e,t,n,r)=>{const s=e.length;let i=e.indexOf(t);return i===-1?!n&&r?e[s-1]:e[0]:(i+=n?1:-1,r&&(i=(i+s)%s),e[Math.max(0,Math.min(i,s-1))])},uw=/[^.]*(?=\..*)\.|.*/,fw=/\..*/,dw=/::\d+$/,pa={};let Yf=1;const kp={mouseenter:"mouseover",mouseleave:"mouseout"},mw=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function $p(e,t){return t&&`${t}::${Yf++}`||e.uidEvent||Yf++}function Dp(e){const t=$p(e);return e.uidEvent=t,pa[t]=pa[t]||{},pa[t]}function hw(e,t){return function n(r){return Lc(r,{delegateTarget:e}),n.oneOff&&H.off(e,r.type,t),t.apply(e,[r])}}function pw(e,t,n){return function r(s){const i=e.querySelectorAll(t);for(let{target:o}=s;o&&o!==this;o=o.parentNode)for(const a of i)if(a===o)return Lc(s,{delegateTarget:o}),r.oneOff&&H.off(e,s.type,t,n),n.apply(o,[s])}}function Mp(e,t,n=null){return Object.values(e).find(r=>r.callable===t&&r.delegationSelector===n)}function Fp(e,t,n){const r=typeof t=="string",s=r?n:t||n;let i=jp(e);return mw.has(i)||(i=e),[r,s,i]}function Kf(e,t,n,r,s){if(typeof t!="string"||!e)return;let[i,o,a]=Fp(t,n,r);t in kp&&(o=(p=>function(v){if(!v.relatedTarget||v.relatedTarget!==v.delegateTarget&&!v.delegateTarget.contains(v.relatedTarget))return p.call(this,v)})(o));const l=Dp(e),u=l[a]||(l[a]={}),c=Mp(u,o,i?n:null);if(c){c.oneOff=c.oneOff&&s;return}const f=$p(o,t.replace(uw,"")),d=i?pw(e,n,o):hw(e,o);d.delegationSelector=i?n:null,d.callable=o,d.oneOff=s,d.uidEvent=f,u[f]=d,e.addEventListener(a,d,i)}function hl(e,t,n,r,s){const i=Mp(t[n],r,s);i&&(e.removeEventListener(n,i,!!s),delete t[n][i.uidEvent])}function gw(e,t,n,r){const s=t[n]||{};for(const[i,o]of Object.entries(s))i.includes(r)&&hl(e,t,n,o.callable,o.delegationSelector)}function jp(e){return e=e.replace(fw,""),kp[e]||e}const H={on(e,t,n,r){Kf(e,t,n,r,!1)},one(e,t,n,r){Kf(e,t,n,r,!0)},off(e,t,n,r){if(typeof t!="string"||!e)return;const[s,i,o]=Fp(t,n,r),a=o!==t,l=Dp(e),u=l[o]||{},c=t.startsWith(".");if(typeof i<"u"){if(!ObLine truncated
`).forEach(function(o){s=o.indexOf(":"),n=o.substring(0,s).trim().toLowerCase(),r=o.substring(s+1).trim(),!(!n||t[n]&&kC[n])&&(n==="set-cookie"?t[n]?t[n].push(r):t[n]=[r]:t[n]=t[n]?t[n]+", "+r:r)}),t},Td=Symbol("internals");function vs(e){return e&&String(e).trim().toLowerCase()}function Ki(e){return e===!1||e==null?e:x.isArray(e)?e.map(Ki):String(e)}function DC(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=n.exec(e);)t[r[1]]=r[2];return t}const MC=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function La(e,t,n,r,s){if(x.isFunction(r))return r.call(this,t,n);if(s&&(t=n),!!x.isString(t)){if(x.isString(r))return t.indexOf(r)!==-1;if(x.isRegExp(r))return r.test(t)}}function FC(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,r)=>n.toUpperCase()+r)}function jC(e,t){const n=x.toCamelCase(" "+t);["get","set","has"].forEach(r=>{Object.defineProperty(e,r+n,{value:function(s,i,o){return this[r].call(this,t,s,i,o)},configurable:!0})})}class gt{constructor(t){t&&this.set(t)}set(t,n,r){const s=this;function i(a,l,u){const c=vs(l);if(!c)throw new Error("header name must be a non-empty string");const f=x.findKey(s,c);(!f||s[f]===void 0||u===!0||u===void 0&&s[f]!==!1)&&(s[f||l]=Ki(a))}const o=(a,l)=>x.forEach(a,(u,c)=>i(u,c,l));if(x.isPlainObject(t)||t instanceof this.constructor)o(t,n);else if(x.isString(t)&&(t=t.trim())&&!MC(t))o($C(t),n);else if(x.isHeaders(t))for(const[a,l]of t.entries())i(l,a,r);else t!=null&&i(n,t,r);return this}get(t,n){if(t=vs(t),t){const r=x.findKey(this,t);if(r){const s=this[r];if(!n)return s;if(n===!0)return DC(s);if(x.isFunction(n))return n.call(this,s,r);if(x.isRegExp(n))return n.exec(s);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=vs(t),t){const r=x.findKey(this,t);return!!(r&&this[r]!==void 0&&(!n||La(this,this[r],r,n)))}return!1}delete(t,n){const r=this;let s=!1;function i(o){if(o=vs(o),o){const a=x.findKey(r,o);a&&(!n||La(r,r[a],a,n))&&(delete r[a],s=!0)}}return x.isArray(t)?t.forEach(i):i(t),s}clear(t){const n=Object.keys(this);let r=n.length,s=!1;for(;r--;){const i=n[r];(!t||La(this,this[i],i,t,!0))&&(delete this[i],s=!0)}return s}normalize(t){const n=this,r={};return x.forEach(this,(s,i)=>{const o=x.findKey(r,i);if(o){n[o]=Ki(s),delete n[i];return}const a=t?FC(i):String(i).trim();a!==i&&delete n[i],n[a]=Ki(s),r[a]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return x.forEach(this,(r,s)=>{r!=null&&r!==!1&&(n[s]=t&&x.isArray(r)?r.join(", "):r)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(`
`)}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const r=new this(t);return n.forEach(s=>r.set(s)),r}static accessor(t){const r=(this[Td]=this[Td]={accessors:{}}).accessors,s=this.prototype;function i(o){const a=vs(o);r[a]||(jC(s,o),r[a]=!0)}return x.isArray(t)?t.forEach(i):i(t),this}}gt.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);x.reduceDescriptors(gt.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(r){this[n]=r}}});x.freezeMethods(gt);function Ia(e,t){const n=this||oi,r=t||n,s=gt.from(r.headers);let i=r.data;return x.forEach(e,function(a){i=a.call(n,i,s.normalize(),t?t.status:void 0)}),s.normalize(),i}function yg(e){return!!(e&&e.__CANCEL__)}function fs(e,t,n){me.call(this,e??"canceled",me.ERR_CANCELED,t,n),this.name="CanceledError"}x.inherits(fs,me,{__CANCEL__:!0});function Eg(e,t,n){const r=n.config.validateStatus;!n.status||!r||r(n.status)?e(n):t(new me("Request failed with status code "+n.status,[me.ERR_BAD_REQUEST,me.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n))}function UC(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function HC(e,t){e=e||10;const n=new Array(e),r=new Array(e);let s=0,i=0,o;return t=t!==void 0?t:1e3,function(l){const u=Date.now(),c=r[i];o||(o=u),n[s]=l,r[s]=u;let f=i,d=0;for(;f!==s;)d+=n[f++],f=f%e;if(s=(s+1)%e,s===i&&(i=(i+1)%e),u-o<t)return;const m=c&&u-c;return m?Math.round(d*1e3/m):void 0}}function VC(e,t){let n=0,r=1e3/t,s,i;const o=(u,c=Date.now())=>{n=c,s=null,i&&(clearTimeout(i),i=null),e.apply(null,u)};return[(...u)=>{const c=Date.now(),f=c-n;f>=r?o(u,c):(s=u,i||(i=setTimeout(()=>{i=null,o(s)},r-f)))},()=>s&&o(s)]}const lo=(e,t,n=3)=>{let r=0;const s=HC(50,250);return VC(i=>{const o=i.loaded,a=i.lengthComputable?i.total:void 0,l=o-r,u=s(l),c=o<=a;r=o;const f={loaded:o,total:a,progress:a?o/a:void 0,bytes:l,rate:u||void 0,estimated:u&&a&&c?(a-o)/u:void 0,event:i,lengthComputable:a!=null,[t?"download":"upload"]:!0};e(f)},n)},Od=(e,t)=>{const n=e!=null;return[r=>t[0]({lengthComputable:n,total:e,loaded:r}),t[1]]},Sd=e=>(...t)=>x.asap(()=>e(...t)),BC=Ft.hasStandardBrowserEnv?function(){const t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");let r;function s(i){let o=i;return t&&(n.setAttribute("href",o),o=n.href),n.setAttribute("href",o),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:n.pathname.charAt(0)==="/"?n.pathname:"/"+n.pathname}}return r=s(window.location.href),function(o){const a=x.isString(o)?s(o):o;return a.protocol===r.protocol&&a.host===r.host}}():function(){return function(){return!0}}(),WC=Ft.hasStandardBrowserEnv?{write(e,t,n,r,s,i){const o=[e+"="+encodeURIComponent(t)];x.isNumber(n)&&o.push("expires="+new Date(n).toGMTString()),x.isString(r)&&o.push("path="+r),x.isString(s)&&o.push("domain="+s),i===!0&&o.push("secure"),document.cookie=o.join("; ")},read(e){const t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove(e){this.write(e,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function YC(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function KC(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function wg(e,t){return e&&!YC(t)?KC(e,t):t}const Cd=e=>e instanceof gt?{...e}:e;function gr(e,t){t=t||{};const n={};function r(u,c,f){return x.isPlainObject(u)&&x.isPlainObject(c)?x.merge.call({caseless:f},u,c):x.isPlainObject(c)?x.merge({},c):x.isArray(c)?c.slice():c}function s(u,c,f){if(x.isUndefined(c)){if(!x.isUndefined(u))return r(void 0,u,f)}else return r(u,c,f)}function i(u,c){if(!x.isUndefined(c))return r(void 0,c)}function o(u,c){if(x.isUndefined(c)){if(!x.isUndefined(u))return r(void 0,u)}else return r(void 0,c)}function a(u,c,f){if(f in t)return r(u,c);if(f in e)return r(void 0,u)}const l={url:i,method:i,data:i,baseURL:o,transformRequest:o,transformResponse:o,paramsSerializer:o,timeout:o,timeoutMessage:o,withCredentials:o,withXSRFToken:o,adapter:o,responseType:o,xsrfCookieName:o,xsrfHeaderName:o,onUploadProgress:o,onDownloadProgress:o,decompress:o,maxContentLength:o,maxBodyLength:o,beforeRedirect:o,transport:o,httpAgent:o,httpsAgent:o,cancelToken:o,socketPath:o,responseEncoding:o,validateStatus:a,headers:(u,c)=>s(Cd(u),Cd(c),!0)};return x.forEach(Object.keys(Object.assign({},e,t)),function(c){const f=l[c]||s,d=f(e[c],t[c],c);x.isUndefined(d)&&f!==a||(n[c]=d)}),n}const Ag=e=>{const t=gr({},e);let{data:n,withXSRFToken:r,xsrfHeaderName:s,xsrfCookieName:i,headers:o,auth:a}=t;t.headers=o=gt.from(o),t.url=_g(wg(t.baseURL,t.url),e.params,e.paramsSerializer),a&&o.set("Authorization","Basic "+btoa((a.username||"")+":"+(a.password?unescape(encodeURIComponent(a.password)):"")));let l;if(x.isFormD Line truncated
`+i.map(Id).join(`
`):" "+Id(i[0]):"as no adapter specified";throw new me("There is no suitable adapter to dispatch the request "+o,"ERR_NOT_SUPPORT")}return r},adapters:El};function Pa(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new fs(null,e)}function Pd(e){return Pa(e),e.headers=gt.from(e.headers),e.data=Ia.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Sg.getAdapter(e.adapter||oi.adapter)(e).then(function(r){return Pa(e),r.data=Ia.call(e,e.transformResponse,r),r.headers=gt.from(r.headers),r},function(r){return yg(r)||(Pa(e),r&&r.response&&(r.response.data=Ia.call(e,e.transformResponse,r.response),r.response.headers=gt.from(r.response.headers))),Promise.reject(r)})}const Cg="1.7.3",Mc={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{Mc[e]=function(r){return typeof r===e||"a"+(t<1?"n ":" ")+e}});const Rd={};Mc.transitional=function(t,n,r){function s(i,o){return"[Axios v"+Cg+"] Transitional option '"+i+"'"+o+(r?". "+r:"")}return(i,o,a)=>{if(t===!1)throw new me(s(o," has been removed"+(n?" in "+n:"")),me.ERR_DEPRECATED);return n&&!Rd[o]&&(Rd[o]=!0,console.warn(s(o," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(i,o,a):!0}};function rN(e,t,n){if(typeof e!="object")throw new me("options must be an object",me.ERR_BAD_OPTION_VALUE);const r=Object.keys(e);let s=r.length;for(;s-- >0;){const i=r[s],o=t[i];if(o){const a=e[i],l=a===void 0||o(a,i,e);if(l!==!0)throw new me("option "+i+" must be "+l,me.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new me("Unknown option "+i,me.ERR_BAD_OPTION)}}const wl={assertOptions:rN,validators:Mc},yn=wl.validators;class fr{constructor(t){this.defaults=t,this.interceptors={request:new Ad,response:new Ad}}async request(t,n){try{return await this._request(t,n)}catch(r){if(r instanceof Error){let s;Error.captureStackTrace?Error.captureStackTrace(s={}):s=new Error;const i=s.stack?s.stack.replace(/^.+\n/,""):"";try{r.stack?i&&!String(r.stack).endsWith(i.replace(/^.+\n.+\n/,""))&&(r.stack+=`
`+i):r.stack=i}catch{}}throw r}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=gr(this.defaults,n);const{transitional:r,paramsSerializer:s,headers:i}=n;r!==void 0&&wl.assertOptions(r,{silentJSONParsing:yn.transitional(yn.boolean),forcedJSONParsing:yn.transitional(yn.boolean),clarifyTimeoutError:yn.transitional(yn.boolean)},!1),s!=null&&(x.isFunction(s)?n.paramsSerializer={serialize:s}:wl.assertOptions(s,{encode:yn.function,serialize:yn.function},!0)),n.method=(n.method||this.defaults.method||"get").toLowerCase();let o=i&&x.merge(i.common,i[n.method]);i&&x.forEach(["delete","get","head","post","put","patch","common"],p=>{delete i[p]}),n.headers=gt.concat(o,i);const a=[];let l=!0;this.interceptors.request.forEach(function(v){typeof v.runWhen=="function"&&v.runWhen(n)===!1||(l=l&&v.synchronous,a.unshift(v.fulfilled,v.rejected))});const u=[];this.interceptors.response.forEach(function(v){u.push(v.fulfilled,v.rejected)});let c,f=0,d;if(!l){const p=[Pd.bind(this),void 0];for(p.unshift.apply(p,a),p.push.apply(p,u),d=p.length,c=Promise.resolve(n);f<d;)c=c.then(p[f++],p[f++]);return c}d=a.length;let m=n;for(f=0;f<d;){const p=a[f++],v=a[f++];try{m=p(m)}catch(y){v.call(this,y);break}}try{c=Pd.call(this,m)}catch(p){return Promise.reject(p)}for(f=0,d=u.length;f<d;)c=c.then(u[f++],u[f++]);return c}getUri(t){t=gr(this.defaults,t);const n=wg(t.baseURL,t.url);return _g(n,t.params,t.paramsSerializer)}}x.forEach(["delete","get","head","options"],function(t){fr.prototype[t]=function(n,r){return this.request(gr(r||{},{method:t,url:n,data:(r||{}).data}))}});x.forEach(["post","put","patch"],function(t){function n(r){return function(i,o,a){return this.request(gr(a||{},{method:t,headers:r?{"Content-Type":"multipart/form-data"}:{},url:i,data:o}))}}fr.prototype[t]=n(),fr.prototype[t+"Form"]=n(!0)});class Fc{constructor(t){if(typeof t!="function")throw new TypeError("executor must be a function.");let n;this.promise=new Promise(function(i){n=i});const r=this;this.promise.then(s=>{if(!r._listeners)return;let i=r._listeners.length;for(;i-- >0;)r._listeners[i](s);r._listeners=null}),this.promise.then=s=>{let i;const o=new Promise(a=>{r.subscribe(a),i=a}).then(s);return o.cancel=function(){r.unsubscribe(i)},o},t(function(i,o,a){r.reason||(r.reason=new fs(i,o,a),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}static source(){let t;return{token:new Fc(function(s){t=s}),cancel:t}}}function sN(e){return function(n){return e.apply(null,n)}}function iN(e){return x.isObject(e)&&e.isAxiosError===!0}const Al={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(Al).forEach(([e,t])=>{Al[t]=e});function Ng(e){const t=new fr(e),n=ig(fr.prototype.request,t);return x.extend(n,fr.prototype,t,{allOwnKeys:!0}),x.extend(n,t,null,{allOwnKeys:!0}),n.create=function(s){return Ng(gr(e,s))},n}const Ue=Ng(oi);Ue.Axios=fr;Ue.CanceledError=fs;Ue.CancelToken=Fc;Ue.isCancel=yg;Ue.VERSION=Cg;Ue.toFormData=Ko;Ue.AxiosError=me;Ue.Cancel=Ue.CanceledError;Ue.all=function(t){return Promise.all(t)};Ue.spread=sN;Ue.isAxiosError=iN;Ue.mergeConfig=gr;Ue.AxiosHeaders=gt;Ue.formToJSON=e=>bg(x.isHTMLForm(e)?new FormData(e):e);Ue.getAdapter=Sg.getAdapter;Ue.HttpStatusCode=Al;Ue.default=Ue;class oN{getTest(t,n){return new Promise((r,s)=>{Ue.get(`${Rs.API_BASE_URL}/user/test/${t}`,{params:{param1:n},withCredentials:!0}).then(i=>{r(i)}).catch(i=>{s(i)})})}}const aN=new oN,ai=e=>(iv("data-v-6c838f03"),e=e(),ov(),e),lN={class:"row"},cN={class:"col"},uN={class:"w-100 d-flex justify-content-center my-5"},fN={class:"container-fluid px-0 d-flex justify-content-center align-items-center flex-column"},dN Line truncated
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function II(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var Vd=function(){},Hc={},jg={},Ug=null,Hg={mark:Vd,measure:Vd};try{typeof window<"u"&&(Hc=window),typeof document<"u"&&(jg=document),typeof MutationObserver<"u"&&(Ug=MutationObserver),typeof performance<"u"&&(Hg=performance)}catch{}var PI=Hc.navigator||{},Bd=PI.userAgent,Wd=Bd===void 0?"":Bd,Mn=Hc,Me=jg,Yd=Ug,Ci=Hg;Mn.document;var pn=!!Me.documentElement&&!!Me.head&&typeof Me.addEventListener=="function"&&typeof Me.createElement=="function",Vg=~Wd.indexOf("MSIE")||~Wd.indexOf("Trident/"),Ni,Li,Ii,Pi,Ri,un="___FONT_AWESOME___",Cl=16,Bg="fa",Wg="svg-inline--fa",_r="data-fa-i2svg",Nl="data-fa-pseudo-element",RI="data-fa-pseudo-element-pending",Vc="data-prefix",Bc="data-icon",Kd="fontawesome-i2svg",xI="async",kI=["HTML","HEAD","STYLE","SCRIPT"],Yg=function(){try{return!0}catch{return!1}}(),$e="classic",Ve="sharp",Wc=[$e,Ve];function ci(e){return new Proxy(e,{get:function(n,r){return r in n?n[r]:n[$e]}})}var Ks=ci((Ni={},qe(Ni,$e,{fa:"solid",fas:"solid","fa-solid":"solid",far:"regular","fa-regular":"regular",fal:"light","fa-light":"light",fat:"thin","fa-thin":"thin",fad:"duotone","fa-duotone":"duotone",fab:"brands","fa-brands":"brands",fak:"kit",fakd:"kit","fa-kit":"kit","fa-kit-duotone":"kit"}),qe(Ni,Ve,{fa:"solid",fass:"solid","fa-solid":"solid",fasr:"regular","fa-regular":"regular",fasl:"light","fa-light":"light",fast:"thin","fa-thin":"thin"}),Ni)),zs=ci((Li={},qe(Li,$e,{solid:"fas",regular:"far",light:"fal",thin:"fat",duotone:"fad",brands:"fab",kit:"fak"}),qe(Li,Ve,{solid:"fass",regular:"fasr",light:"fasl",thin:"fast"}),Li)),Gs=ci((Ii={},qe(Ii,$e,{fab:"fa-brands",fad:"fa-duotone",fak:"fa-kit",fal:"fa-light",far:"fa-regular",fas:"fa-solid",fat:"fa-thin"}),qe(Ii,Ve,{fass:"fa-solid",fasr:"fa-regular",fasl:"fa-light",fast:"fa-thin"}),Ii)),$I=ci((Pi={},qe(Pi,$e,{"fa-brands":"fab","fa-duotone":"fad","fa-kit":"fak","fa-light":"fal","fa-regular":"far","fa-solid":"fas","fa-thin":"fat"}),qe(Pi,Ve,{"fa-solid":"fass","fa-regular":"fasr","fa-light":"fasl","fa-thin":"fast"}),Pi)),DI=/fa(s|r|l|t|d|b|k|ss|sr|sl|st)?[\-\ ]/,Kg="fa-layers-text",MI=/Font ?Awesome ?([56 ]*)(Solid|Regular|Light|Thin|Duotone|Brands|Free|Pro|Sharp|Kit)?.*/i,FI=ci((Ri={},qe(Ri,$e,{900:"fas",400:"far",normal:"far",300:"fal",100:"fat"}),qe(Ri,Ve,{900:"fass",400:"fasr",300:"fasl",100:"fast"}),Ri)),zg=[1,2,3,4,5,6,7,8,9,10],jI=zg.concat([11,12,13,14,15,16,17,18,19,20]),UI=["class","data-prefix","data-icon","data-fa-transform","data-fa-mask"],ir={GROUP:"duotone-group",SWAP_OPACITY:"swap-opacity",PRIMARY:"primary",SECONDARY:"secondary"},qs=new Set;Object.keys(zs[$e]).map(qs.add.bind(qs));Object.keys(zs[Ve]).map(qs.add.bind(qs));var HI=[].concat(Wc,li(qs),["2xs","xs","sm","lg","xl","2xl","beat","border","fade","beat-fade","bounce","flip-both","flip-horizontal","flip-vertical","flip","fw","inverse","layers-counter","layers-text","layers","li","pull-left","pull-right","pulse","rotate-180","rotate-270","rotate-90","rotate-by","shake","spin-pulse","spin-reverse","spin","stack-1x","stack-2x","stack","ul",ir.GROUP,ir.SWAP_OPACITY,ir.PRIMARY,ir.SECONDARY]).concat(zg.map(function(e){return"".concat(e,"x")})).concat(jI.map(function(e){return"w-".concat(e)})),xs=Mn.FontAwesomeConfig||{};function VI(e){var t=Me.querySelector("script["+e+"]");if(t)return t.getAttribute(e)}function BI(e){return e===""?!0:e==="false"?!1:e==="true"?!0:e}if(Me&&typeof Me.querySelector=="function"){var WI=[["data-family-prefix","familyPrefix"],["data-css-prefix","cssPrefix"],["data-family-default","familyDefault"],["data-style-default","styleDefault"],["data-replacement-class","replacementClass"],["data-auto-replace-svg","autoReplaceSvg"],["data-auto-add-css","autoAddCss"],["data-auto-a11y","autoA11y"],["data-search-pseudo-elements","searchPseudoElements"],["data-observe-mutations","observeMutations"],["data-mutate-approach","mutateApproach"],["data-keep-original-source","keepOriginalSource"],["data-measure-performance","measurePerformance"],["data-show-missing-icons","showMissingIcons"]];WI.forEach(function(e){var t=Uc(e,2),n=t[0],r=t[1],s=BI(VI(n));s!=null&&(xs[r]=s)})}var Gg={styleDefault:"solid",familyDefault:"classic",cssPrefix:Bg,replacementClass:Wg,autoReplaceSvg:!0,autoAddCss:!0,autoA11y:!0,searchPseudoElements:!1,observeMutations:!0,mutateApproach:"async",keepOriginalSource:!0,measurePerformance:!1,showMissingIcons:!0};xs.familyPrefix&&(xs.cssPrefix=xs.familyPrefix);var ns=X(X({},Gg),xs);ns.autoReplaceSvg||(ns.observeMutations=!1);var Z={};Object.keys(Gg).forEach(function(e){Object.defineProperty(Z,e,{enumerable:!0,set:function(n){ns[e]=n,ks.forEach(function(r){return r(Z)})},get:function(){return ns[e]}})});Object.defineProperty(Z,"familyPrefix",{enumerable:!0,set:function(t){ns.cssPrefix=t,ks.forEach(function(n){return n(Z)})},get:function(){return ns.cssPrefix}});Mn.FontAwesomeConfig=Z;var ks=[];function YI(e){return ks.push(e),function(){ks.splice(ks.indexOf(e),1)}}var En=Cl,zt={size:16,x:0 Line truncated
--fa-font-solid: normal 900 1em/1 "Font Awesome 6 Solid";
--fa-font-regular: normal 400 1em/1 "Font Awesome 6 Regular";
--fa-font-light: normal 300 1em/1 "Font Awesome 6 Light";
--fa-font-thin: normal 100 1em/1 "Font Awesome 6 Thin";
--fa-font-duotone: normal 900 1em/1 "Font Awesome 6 Duotone";
--fa-font-sharp-solid: normal 900 1em/1 "Font Awesome 6 Sharp";
--fa-font-sharp-regular: normal 400 1em/1 "Font Awesome 6 Sharp";
--fa-font-sharp-light: normal 300 1em/1 "Font Awesome 6 Sharp";
--fa-font-sharp-thin: normal 100 1em/1 "Font Awesome 6 Sharp";
--fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands";
}
svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {
overflow: visible;
box-sizing: content-box;
}
.svg-inline--fa {
display: var(--fa-display, inline-block);
height: 1em;
overflow: visible;
vertical-align: -0.125em;
}
.svg-inline--fa.fa-2xs {
vertical-align: 0.1em;
}
.svg-inline--fa.fa-xs {
vertical-align: 0em;
}
.svg-inline--fa.fa-sm {
vertical-align: -0.0714285705em;
}
.svg-inline--fa.fa-lg {
vertical-align: -0.2em;
}
.svg-inline--fa.fa-xl {
vertical-align: -0.25em;
}
.svg-inline--fa.fa-2xl {
vertical-align: -0.3125em;
}
.svg-inline--fa.fa-pull-left {
margin-right: var(--fa-pull-margin, 0.3em);
width: auto;
}
.svg-inline--fa.fa-pull-right {
margin-left: var(--fa-pull-margin, 0.3em);
width: auto;
}
.svg-inline--fa.fa-li {
width: var(--fa-li-width, 2em);
top: 0.25em;
}
.svg-inline--fa.fa-fw {
width: var(--fa-fw-width, 1.25em);
}
.fa-layers svg.svg-inline--fa {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
}
.fa-layers-counter, .fa-layers-text {
display: inline-block;
position: absolute;
text-align: center;
}
.fa-layers {
display: inline-block;
height: 1em;
position: relative;
text-align: center;
vertical-align: -0.125em;
width: 1em;
}
.fa-layers svg.svg-inline--fa {
-webkit-transform-origin: center center;
transform-origin: center center;
}
.fa-layers-text {
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transform-origin: center center;
transform-origin: center center;
}
.fa-layers-counter {
background-color: var(--fa-counter-background-color, #ff253a);
border-radius: var(--fa-counter-border-radius, 1em);
box-sizing: border-box;
color: var(--fa-inverse, #fff);
line-height: var(--fa-counter-line-height, 1);
max-width: var(--fa-counter-max-width, 5em);
min-width: var(--fa-counter-min-width, 1.5em);
overflow: hidden;
padding: var(--fa-counter-padding, 0.25em 0.5em);
right: var(--fa-right, 0);
text-overflow: ellipsis;
top: var(--fa-top, 0);
-webkit-transform: scale(var(--fa-counter-scale, 0.25));
transform: scale(var(--fa-counter-scale, 0.25));
-webkit-transform-origin: top right;
transform-origin: top right;
}
.fa-layers-bottom-right {
bottom: var(--fa-bottom, 0);
right: var(--fa-right, 0);
top: auto;
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: bottom right;
transform-origin: bottom right;
}
.fa-layers-bottom-left {
bottom: var(--fa-bottom, 0);
left: var(--fa-left, 0);
right: auto;
top: auto;
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: bottom left;
transform-origin: bottom left;
}
.fa-layers-top-right {
top: var(--fa-top, 0);
right: var(--fa-right, 0);
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: top right;
transform-origin: top right;
}
.fa-layers-top-left {
left: var(--fa-left, 0);
right: auto;
top: var(--fa-top, 0);
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: top left;
transform-origin: top left;
}
.fa-1x {
font-size: 1em;
}
.fa-2x {
font-size: 2em;
}
.fa-3x {
font-size: 3em;
}
.fa-4x {
font-size: 4em;
}
.fa-5x {
font-size: 5em;
}
.fa-6x {
font-size: 6em;
}
.fa-7x {
font-size: 7em;
}
.fa-8x {
font-size: 8em;
}
.fa-9x {
font-size: 9em;
}
.fa-10x {
font-size: 10em;
}
.fa-2xs {
font-size: 0.625em;
line-height: 0.1em;
vertical-align: 0.225em;
}
.fa-xs {
font-size: 0.75em;
line-height: 0.0833333337em;
vertical-align: 0.125em;
}
.fa-sm {
font-size: 0.875em;
line-height: 0.0714285718em;
vertical-align: 0.0535714295em;
}
.fa-lg {
font-size: 1.25em;
line-height: 0.05em;
vertical-align: -0.075em;
}
.fa-xl {
font-size: 1.5em;
line-height: 0.0416666682em;
vertical-align: -0.125em;
}
.fa-2xl {
font-size: 2em;
line-height: 0.03125em;
vertical-align: -0.1875em;
}
.fa-fw {
text-align: center;
width: 1.25em;
}
.fa-ul {
list-style-type: none;
margin-left: var(--fa-li-margin, 2.5em);
padding-left: 0;
}
.fa-ul > li {
position: relative;
}
.fa-li {
left: calc(var(--fa-li-width, 2em) * -1);
position: absolute;
text-align: center;
width: var(--fa-li-width, 2em);
line-height: inherit;
}
.fa-border {
border-color: var(--fa-border-color, #eee);
border-radius: var(--fa-border-radius, 0.1em);
border-style: var(--fa-border-style, solid);
border-width: var(--fa-border-width, 0.08em);
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em);
}
.fa-pull-left {
float: left;
margin-right: var(--fa-pull-margin, 0.3em);
}
.fa-pull-right {
float: right;
margin-left: var(--fa-pull-margin, 0.3em);
}
.fa-beat {
-webkit-animation-name: fa-beat;
animation-name: fa-beat;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
animation-timing-function: var(--fa-animation-timing, ease-in-out);
}
.fa-bounce {
-webkit-animation-name: fa-bounce;
animation-name: fa-bounce;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
}
.fa-fade {
-webkit-animation-name: fa-fade;
animation-name: fa-fade;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
}
.fa-beat-fade {
-webkit-animation-name: fa-beat-fade;
animation-name: fa-beat-fade;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
}
.fa-flip {
-webkit-animation-name: fa-flip;
animation-name: fa-flip;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
animation-timing-function: var(--fa-animation-timing, ease-in-out);
}
.fa-shake {
-webkit-animation-name: fa-shake;
animation-name: fa-shake;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
animation-timing-function: var(--fa-animation-timing, linear);
}
.fa-spin {
-webkit-animation-name: fa-spin;
animation-name: fa-spin;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 2s);
animation-duration: var(--fa-animation-duration, 2s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
animation-timing-function: var(--fa-animation-timing, linear);
}
.fa-spin-reverse {
--fa-animation-direction: reverse;
}
.fa-pulse,
.fa-spin-pulse {
-webkit-animation-name: fa-spin;
animation-name: fa-spin;
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
animation-timing-function: var(--fa-animation-timing, steps(8));
}
@media (prefers-reduced-motion: reduce) {
.fa-beat,
.fa-bounce,
.fa-fade,
.fa-beat-fade,
.fa-flip,
.fa-pulse,
.fa-shake,
.fa-spin,
.fa-spin-pulse {
-webkit-animation-delay: -1ms;
animation-delay: -1ms;
-webkit-animation-duration: 1ms;
animation-duration: 1ms;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
-webkit-transition-delay: 0s;
transition-delay: 0s;
-webkit-transition-duration: 0s;
transition-duration: 0s;
}
}
@-webkit-keyframes fa-beat {
0%, 90% {
-webkit-transform: scale(1);
transform: scale(1);
}
45% {
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
transform: scale(var(--fa-beat-scale, 1.25));
}
}
@keyframes fa-beat {
0%, 90% {
-webkit-transform: scale(1);
transform: scale(1);
}
45% {
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
transform: scale(var(--fa-beat-scale, 1.25));
}
}
@-webkit-keyframes fa-bounce {
0% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0);
}
10% {
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
}
30% {
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
}
50% {
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
}
57% {
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
}
64% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0);
}
100% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0);
}
}
@keyframes fa-bounce {
0% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0);
}
10% {
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
}
30% {
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
}
50% {
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
}
57% {
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
}
64% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0);
}
100% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0);
}
}
@-webkit-keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4);
}
}
@keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4);
}
}
@-webkit-keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
-webkit-transform: scale(1);
transform: scale(1);
}
50% {
opacity: 1;
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
transform: scale(var(--fa-beat-fade-scale, 1.125));
}
}
@keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
-webkit-transform: scale(1);
transform: scale(1);
}
50% {
opacity: 1;
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
transform: scale(var(--fa-beat-fade-scale, 1.125));
}
}
@-webkit-keyframes fa-flip {
50% {
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
}
}
@keyframes fa-flip {
50% {
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
}
}
@-webkit-keyframes fa-shake {
0% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
4% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg);
}
8%, 24% {
-webkit-transform: rotate(-18deg);
transform: rotate(-18deg);
}
12%, 28% {
-webkit-transform: rotate(18deg);
transform: rotate(18deg);
}
16% {
-webkit-transform: rotate(-22deg);
transform: rotate(-22deg);
}
20% {
-webkit-transform: rotate(22deg);
transform: rotate(22deg);
}
32% {
-webkit-transform: rotate(-12deg);
transform: rotate(-12deg);
}
36% {
-webkit-transform: rotate(12deg);
transform: rotate(12deg);
}
40%, 100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
}
@keyframes fa-shake {
0% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
4% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg);
}
8%, 24% {
-webkit-transform: rotate(-18deg);
transform: rotate(-18deg);
}
12%, 28% {
-webkit-transform: rotate(18deg);
transform: rotate(18deg);
}
16% {
-webkit-transform: rotate(-22deg);
transform: rotate(-22deg);
}
20% {
-webkit-transform: rotate(22deg);
transform: rotate(22deg);
}
32% {
-webkit-transform: rotate(-12deg);
transform: rotate(-12deg);
}
36% {
-webkit-transform: rotate(12deg);
transform: rotate(12deg);
}
40%, 100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.fa-rotate-90 {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.fa-rotate-180 {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
.fa-rotate-270 {
-webkit-transform: rotate(270deg);
transform: rotate(270deg);
}
.fa-flip-horizontal {
-webkit-transform: scale(-1, 1);
transform: scale(-1, 1);
}
.fa-flip-vertical {
-webkit-transform: scale(1, -1);
transform: scale(1, -1);
}
.fa-flip-both,
.fa-flip-horizontal.fa-flip-vertical {
-webkit-transform: scale(-1, -1);
transform: scale(-1, -1);
}
.fa-rotate-by {
-webkit-transform: rotate(var(--fa-rotate-angle, 0));
transform: rotate(var(--fa-rotate-angle, 0));
}
.fa-stack {
display: inline-block;
vertical-align: middle;
height: 2em;
position: relative;
width: 2.5em;
}
.fa-stack-1x,
.fa-stack-2x {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
z-index: var(--fa-stack-z-index, auto);
}
.svg-inline--fa.fa-stack-1x {
height: 1em;
width: 1.25em;
}
.svg-inline--fa.fa-stack-2x {
height: 2em;
width: 2.5em;
}
.fa-inverse {
color: var(--fa-inverse, #fff);
}
.sr-only,
.fa-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.sr-only-focusable:not(:focus),
.fa-sr-only-focusable:not(:focus) {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.svg-inline--fa .fa-primary {
fill: var(--fa-primary-color, currentColor);
opacity: var(--fa-primary-opacity, 1);
}
.svg-inline--fa .fa-secondary {
fill: var(--fa-secondary-color, currentColor);
opacity: var(--fa-secondary-opacity, 0.4);
}
.svg-inline--fa.fa-swap-opacity .fa-primary {
opacity: var(--fa-secondary-opacity, 0.4);
}
.svg-inline--fa.fa-swap-opacity .fa-secondary {
opacity: var(--fa-primary-opacity, 1);
}
.svg-inline--fa mask .fa-primary,
.svg-inline--fa mask .fa-secondary {
fill: black;
}
.fad.fa-inverse,
.fa-duotone.fa-inverse {
color: var(--fa-inverse, #fff);
}`;function Xg(){var e=Bg,t=Wg,n=Z.cssPrefix,r=Z.replacementClass,s=JI;if(n!==e||r!==t){var i=new RegExp("\\.".concat(e,"\\-"),"g"),o=new RegExp("\\--".concat(e,"\\-"),"g"),a=new RegExp("\\.".concat(t),"g");s=s.replace(i,".".concat(n,"-")).replace(o,"--".concat(n,"-")).replace(a,".".concat(r))}return s}var zd=!1;function xa(){Z.autoAddCss&&!zd&&(KI(Xg()),zd=!0)}var QI={mixout:function(){return{dom:{css:Xg,insertCss:xa}}},hooks:function(){return{beforeDOMElementCreation:function(){xa()},beforeI2svg:function(){xa()}}}},fn=Mn||{};fn[un]||(fn[un]={});fn[un].styles||(fn[un].styles={});fn[un].hooks||(fn[un].hooks={});fn[un].shims||(fn[un].shims=[]);var Dt=fn[un],Jg=[],ZI=function e(){Me.removeEventListener("DOMContentLoaded",e),mo=1,Jg.map(function(t){return t()})},mo=!1;pn&&(mo=(Me.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(Me.readyState),mo||Me.addEventListener("DOMContentLoaded",ZI));function eP(e){pn&&(mo?setTimeout(e,0):Jg.push(e))}function ui(e){var t=e.tag,n=e.attributes,r=n===void 0?{}:n,s=e.children,i=s===void 0?[]:s;return typeof e=="string"?qg(e):"<".concat(t," ").concat(GI(r),">").concat(i.map(ui).join(""),"</").concat(t,">")}function Gd(e,t,n){if(e&&e[t]&&e[t][n])return{prefix:t,iconName:n,icon:e[t][n]}}var ka=function(t,n,r,s){var i=Object.keys(t),o=i.length,a=n,l,u,c;for(r===void 0?(l=1,c=t[i[0]]):(l=0,c=r);l<o;l++)u=i[l],c=a(c,t[u],u,t);return c};function tP(e){for(var t=[],n=0,r=e.length;n<r;){var s=e.charCodeAt(n++);if(s>=55296&&s<=56319&&n<r){var i=e.charCodeAt(n++);(i&64512)==56320?t.push(((s&1023)<<10)+(i&1023)+65536):(t.push(s),n--)}else t.push(s)}return t}function Ll(e){var t=tP(e);return t.length===1?t[0].toString(16):null}function nP(e,t){var n=e.length,r=e.charCodeAt(t),s;return r>=55296&&r<=56319&&n>t+1&&(s=e.charCodeAt(t+1),s>=56320&&s<=57343)?(r-55296)*1024+s-56320+65536:r}function qd(e){return Object.keys(e).reduce(function(t,n){var r=e[n],s=!!r.icon;return s?t[r.iconName]=r.icon:t[n]=r,t},{})}function Il(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=n.skipHooks,s=r===void 0?!1:r,i=qd(t);typeof Dt.hooks.addPack=="function"&&!s?Dt.hooks.addPack(e,qd(t)):Dt.styles[e]=X(X({},Dt.styles[e]||{}),i),e==="fas"&&Il("fa",t)}var xi,ki,$i,$r=Dt.styles,rP=Dt.shims,sP=(xi={},qe(xi,$e,Object.values(Gs[$e])),qe(xi,Ve,Object.values(Gs[Ve])),xi),zc=null,Qg={},Zg={},e_={},t_={},n_={},iP=(ki={},qe(ki,$e,Object.keys(Ks[$e])),qe(ki,Ve,Object.keys(Ks[Ve])),ki);function oP(e){return~HI.indexOf(e)}function aP(e,t){var n=t.split("-"),r=n[0],s=n.slice(1).join("-");return r===e&&s!==""&&!oP(s)?s:null}var r_=function(){var t=function(i){return ka($r,function(o,a,l){return o[l]=ka(a,i,{}),o},{})};Qg=t(function(s,i,o){if(i[3]&&(s[i[3]]=o),i[2]){var a=i[2].filter(function(l){return typeof l=="number"});a.forEach(function(l){s[l.toString(16)]=o})}return s}),Zg=t(function(s,i,o){if(s[o]=o,i[2]){var a=i[2].filter(function(l){return typeof l=="string"});a.forEach(function(l){s[l]=o})}return s}),n_=t(function(s,i,o){var a=i[2];return s[o]=o,a.forEach(function(l){s[l]=o}),s});var n="far"in $r||Z.autoFetchSvg,r=ka(rP,function(s,i){var o=i[0],a=i[1],l=i[2];return a==="far"&&!n&&(a="fas"),typeof o=="string"&&(s.names[o]={prefix:a,iconName:l}),typeof o=="number"&&(s.unicodes[o.toString(16)]={prefix:a,iconName:l}),s},{names:{},unicodes:{}});e_=r.names,t_=r.unicodes,zc=qo(Z.styleDefault,{family:Z.familyDefault})};YI(function(e){zc=qo(e.styleDefault,{family:Z.familyDefault})});r_();function Gc(e,t){return(Qg[e]||{})[t]}function lP(e,t){return(Zg[e]||{})[t]}function or(e,t){return(n_[e]||{})[t]}function s_(e){return e_[e]||{prefix:null,iconName:null}}function cP(e){var t=t_[e],n=Gc("fas",e);return t||(n?{prefix:"fas",iconName:n}:null)||{prefix:null,iconName:null}}function Fn(){return zc}var qc=function(){return{prefix:null,iconName:null,rest:[]}};function qo(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=t.family,r=n===void 0?$e:n,s=Ks[r][e],i=zs[r][e]||zs[r][s],o=e in Dt.styles?e:null;return i||o||null}var Xd=($i={},qe($i,$e,Object.keys(Gs[$e])),qe($i,Ve,Object.keys(Gs[Ve])),$i);function Xo(e){var t,n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=n.skipLookups,s=r===void 0?!1:r,i=(t={},qe(t,$e,"".concat(Z.cssPrefix,"-").concat($e)),qe(t,Ve,"".concat(Z.cssPrefix,"-").concat(Ve)),t),o=null,a=$e;(e.includes(i[$e])||e.some(function(u){return Xd[$e].includes(u)}))&&(a=$e),(e.includes(i[Ve])||e.some(function(u){return Xd[Ve].includes(u)}))&&(a=Ve);var l=e.reduce(function(u,c){var f=aP(Z.cssPrefix,c);if($r[c]?(c=sP[a].includes(c)?$I[a][c]:c,o=c,u.prefix=c):iP[a].indexOf(c)>-1?(o=c,u.prefix=qo(c,{family:a})):f?u.iconName=f:c!==Z.replacementClass&&c!==i[$e]&&c!==i[Ve]&&u.rest.push(c),!s&&u.prefix&&u.iconName){var d=o==="fa"?s_(u.iconName):{},m=or(u.prefix,u.iconName);d.prefix&&(o=null),u.iconName=d.iconName||m||u.iconName,u.prefix=d.prefix||u.prefix,u.prefix==="far"&&!$r.far&&$r.fas&&!Z.autoFetchSvg&&(u.prefix="fas")}return u},qc());return(e.includes("fa-bran Line truncated
`);n.setAttribute(_r,""),n.innerHTML=o}};function tm(e){e()}function l_(e,t){var n=typeof t=="function"?t:Gi;if(e.length===0)n();else{var r=tm;Z.mutateApproach===xI&&(r=Mn.requestAnimationFrame||tm),r(function(){var s=OP(),i=Jc.begin("mutate");e.map(s),i(),n()})}}var Qc=!1;function c_(){Qc=!0}function Dl(){Qc=!1}var ho=null;function nm(e){if(Yd&&Z.observeMutations){var t=e.treeCallback,n=t===void 0?Gi:t,r=e.nodeCallback,s=r===void 0?Gi:r,i=e.pseudoElementsCallback,o=i===void 0?Gi:i,a=e.observeMutationsRoot,l=a===void 0?Me:a;ho=new Yd(function(u){if(!Qc){var c=Fn();ds(u).forEach(function(f){if(f.type==="childList"&&f.addedNodes.length>0&&!em(f.addedNodes[0])&&(Z.searchPseudoElements&&o(f.target),n(f.target)),f.type==="attributes"&&f.target.parentNode&&Z.searchPseudoElements&&o(f.target.parentNode),f.type==="attributes"&&em(f.target)&&~UI.indexOf(f.attributeName))if(f.attributeName==="class"&&AP(f.target)){var d=Xo(Yc(f.target)),m=d.prefix,p=d.iconName;f.target.setAttribute(Vc,m||c),p&&f.target.setAttribute(Bc,p)}else TP(f.target)&&s(f.target)})}}),pn&&ho.observe(l,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}}function LP(){ho&&ho.disconnect()}function IP(e){var t=e.getAttribute("style"),n=[];return t&&(n=t.split(";").reduce(function(r,s){var i=s.split(":"),o=i[0],a=i.slice(1);return o&&a.length>0&&(r[o]=a.join(":").trim()),r},{})),n}function PP(e){var t=e.getAttribute("data-prefix"),n=e.getAttribute("data-icon"),r=e.innerText!==void 0?e.innerText.trim():"",s=Xo(Yc(e));return s.prefix||(s.prefix=Fn()),t&&n&&(s.prefix=t,s.iconName=n),s.iconName&&s.prefix||(s.prefix&&r.length>0&&(s.iconName=lP(s.prefix,e.innerText)||Gc(s.prefix,Ll(e.innerText))),!s.iconName&&Z.autoFetchSvg&&e.firstChild&&e.firstChild.nodeType===Node.TEXT_NODE&&(s.iconName=e.firstChild.data)),s}function RP(e){var t=ds(e.attributes).reduce(function(s,i){return s.name!=="class"&&s.name!=="style"&&(s[i.name]=i.value),s},{}),n=e.getAttribute("title"),r=e.getAttribute("data-fa-title-id");return Z.autoA11y&&(n?t["aria-labelledby"]="".concat(Z.replacementClass,"-title-").concat(r||Xs()):(t["aria-hidden"]="true",t.focusable="false")),t}function xP(){return{iconName:null,title:null,titleId:null,prefix:null,transform:zt,symbol:!1,mask:{iconName:null,prefix:null,rest:[]},maskId:null,extra:{classes:[],styles:{},attributes:{}}}}function rm(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{styleParser:!0},n=PP(e),r=n.iconName,s=n.prefix,i=n.rest,o=RP(e),a=Pl("parseNodeAttributes",{},e),l=t.styleParser?IP(e):[];return X({iconName:r,title:e.getAttribute("title"),titleId:e.getAttribute("data-fa-title-id"),prefix:s,transform:zt,mask:{iconName:null,prefix:null,rest:[]},maskId:null,symbol:!1,extra:{classes:i,styles:l,attributes:o}},a)}var kP=Dt.styles;function u_(e){var t=Z.autoReplaceSvg==="nest"?rm(e,{styleParser:!1}):rm(e);return~t.extra.classes.indexOf(Kg)?dn("generateLayersText",e,t):dn("generateSvgReplacementMutation",e,t)}var jn=new Set;Wc.map(function(e){jn.add("fa-".concat(e))});Object.keys(Ks[$e]).map(jn.add.bind(jn));Object.keys(Ks[Ve]).map(jn.add.bind(jn));jn=li(jn);function sm(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;if(!pn)return Promise.resolve();var n=Me.documentElement.classList,r=function(f){return n.add("".concat(Kd,"-").concat(f))},s=function(f){return n.remove("".concat(Kd,"-").concat(f))},i=Z.autoFetchSvg?jn:Wc.map(function(c){return"fa-".concat(c)}).concat(Object.keys(kP));i.includes("fa")||i.push("fa");var o=[".".concat(Kg,":not([").concat(_r,"])")].concat(i.map(function(c){return".".concat(c,":not([").concat(_r,"])")})).join(", ");if(o.length===0)return Promise.resolve();var a=[];try{a=ds(e.querySelectorAll(o))}catch{}if(a.length>0)r("pending"),s("complete");else return Promise.resolve();var l=Jc.begin("onTree"),u=a.reduce(function(c,f){try{var d=u_(f);d&&c.push(d)}catch(m){Yg||m.name==="MissingIcon"&&console.error(m)}return c},[]);return new Promise(function(c,f){Promise.all(u).then(function(d){l_(d,function(){r("active"),r("complete"),s("pending"),typeof t=="function"&&t(),l(),c()})}).catch(function(d){l(),f(d)})})}function $P(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;u_(e).then(function(n){n&&l_([n],t)})}function DP(e){return function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=(t||{}).icon?t:Rl(t||{}),s=n.mask;return s&&(s=(s||{}).icon?s:Rl(s||{})),e(r,X(X({},n),{},{mask:s}))}}var MP=function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=n.transform,s=r===void 0?zt:r,i=n.symbol,o=i===void 0?!1:i,a=n.mask,l=a===void 0?null:a,u=n.maskId,c=u===void 0?null:u,f=n.title,d=f===void 0?null:f,m=n.titleId,p=m===void 0?null:m,v=n.classes,y=v===void 0?[]:v,w=n.attributes,S=w===void 0?{}:w,E=n.styles,A=E===void 0?{}:E;if(t){var C=t.prefix,O=t.iconName,I=t.icon;return Jo(X({type:"icon"},t),function(){return vr("beforeDOMElementCreation",{iconDefinition:t,params:n}),Z.autoA11y&&(d?S["aria-labelledby"]="".concat(Z.replacem Line truncated
`),e.removeAttribute(n),r()}).catch(s)}else r()}else r()})}function WP(e){return Promise.all([om(e,"::before"),om(e,"::after")])}function YP(e){return e.parentNode!==document.head&&!~kI.indexOf(e.tagName.toUpperCase())&&!e.getAttribute(Nl)&&(!e.parentNode||e.parentNode.tagName!=="svg")}function am(e){if(pn)return new Promise(function(t,n){var r=ds(e.querySelectorAll("*")).filter(YP).map(WP),s=Jc.begin("searchPseudoElements");c_(),Promise.all(r).then(function(){s(),Dl(),t()}).catch(function(){s(),Dl(),n()})})}var KP={hooks:function(){return{mutationObserverCallbacks:function(n){return n.pseudoElementsCallback=am,n}}},provides:function(t){t.pseudoElements2svg=function(n){var r=n.node,s=r===void 0?Me:r;Z.searchPseudoElements&&am(s)}}},lm=!1,zP={mixout:function(){return{dom:{unwatch:function(){c_(),lm=!0}}}},hooks:function(){return{bootstrap:function(){nm(Pl("mutationObserverCallbacks",{}))},noAuto:function(){LP()},watch:function(n){var r=n.observeMutationsRoot;lm?Dl():nm(Pl("mutationObserverCallbacks",{observeMutationsRoot:r}))}}}},cm=function(t){var n={size:16,x:0,y:0,flipX:!1,flipY:!1,rotate:0};return t.toLowerCase().split(" ").reduce(function(r,s){var i=s.toLowerCase().split("-"),o=i[0],a=i.slice(1).join("-");if(o&&a==="h")return r.flipX=!0,r;if(o&&a==="v")return r.flipY=!0,r;if(a=parseFloat(a),isNaN(a))return r;switch(o){case"grow":r.size=r.size+a;break;case"shrink":r.size=r.size-a;break;case"left":r.x=r.x-a;break;case"right":r.x=r.x+a;break;case"up":r.y=r.y-a;break;case"down":r.y=r.y+a;break;case"rotate":r.rotate=r.rotate+a;break}return r},n)},GP={mixout:function(){return{parse:{transform:function(n){return cm(n)}}}},hooks:function(){return{parseNodeAttributes:function(n,r){var s=r.getAttribute("data-fa-transform");return s&&(n.transform=cm(s)),n}}},provides:function(t){t.generateAbstractTransformGrouping=function(n){var r=n.main,s=n.transform,i=n.containerWidth,o=n.iconWidth,a={transform:"translate(".concat(i/2," 256)")},l="translate(".concat(s.x*32,", ").concat(s.y*32,") "),u="scale(".concat(s.size/16*(s.flipX?-1:1),", ").concat(s.size/16*(s.flipY?-1:1),") "),c="rotate(".concat(s.rotate," 0 0)"),f={transform:"".concat(l," ").concat(u," ").concat(c)},d={transform:"translate(".concat(o/2*-1," -256)")},m={outer:a,inner:f,path:d};return{tag:"g",attributes:X({},m.outer),children:[{tag:"g",attributes:X({},m.inner),children:[{tag:r.icon.tag,children:r.icon.children,attributes:X(X({},r.icon.attributes),m.path)}]}]}}}},Da={x:0,y:0,width:"100%",height:"100%"};function um(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return e.attributes&&(e.attributes.fill||t)&&(e.attributes.fill="black"),e}function qP(e){return e.tag==="g"?e.children:[e]}var XP={hooks:function(){return{parseNodeAttributes:function(n,r){var s=r.getAttribute("data-fa-mask"),i=s?Xo(s.split(" ").map(function(o){return o.trim()})):qc();return i.prefix||(i.prefix=Fn()),n.mask=i,n.maskId=r.getAttribute("data-fa-mask-id"),n}}},provides:function(t){t.generateAbstractMask=function(n){var r=n.children,s=n.attributes,i=n.main,o=n.mask,a=n.maskId,l=n.transform,u=i.width,c=i.icon,f=o.width,d=o.icon,m=qI({transform:l,containerWidth:f,iconWidth:u}),p={tag:"rect",attributes:X(X({},Da),{},{fill:"white"})},v=c.children?{children:c.children.map(um)}:{},y={tag:"g",attributes:X({},m.inner),children:[um(X({tag:c.tag,attributes:X(X({},c.attributes),m.path)},v))]},w={tag:"g",attributes:X({},m.outer),children:[y]},S="mask-".concat(a||Xs()),E="clip-".concat(a||Xs()),A={tag:"mask",attributes:X(X({},Da),{},{id:S,maskUnits:"userSpaceOnUse",maskContentUnits:"userSpaceOnUse"}),children:[p,w]},C={tag:"defs",children:[{tag:"clipPath",attributes:{id:E},children:qP(d)},A]};return r.push(C,{tag:"rect",attributes:X({fill:"currentColor","clip-path":"url(#".concat(E,")"),mask:"url(#".concat(S,")")},Da)}),{children:r,attributes:s}}}},JP={provides:function(t){var n=!1;Mn.matchMedia&&(n=Mn.matchMedia("(prefers-reduced-motion: reduce)").matches),t.missingIconAbstract=function(){var r=[],s={fill:"currentColor"},i={attributeType:"XML",repeatCount:"indefinite",dur:"2s"};r.push({tag:"path",attributes:X(X({},s),{},{d:"M156.5,447.7l-12.6,29.5c-18.7-9.5-35.9-21.2-51.5-34.9l22.7-22.7C127.6,430.5,141.5,440,156.5,447.7z M40.6,272H8.5 c1.4,21.2,5.4,41.7,11.7,61.1L50,321.2C45.1,305.5,41.8,289,40.6,272z M40.6,240c1.4-18.8,5.2-37,11.1-54.1l-29.5-12.6 C14.7,194.3,10,216.7,8.5,240H40.6z M64.3,156.5c7.8-14.9,17.2-28.8,28.1-41.5L69.7,92.3c-13.7,15.6-25.5,32.8-34.9,51.5 L64.3,156.5z M397,419.6c-13.9,12-29.4,22.3-46.1,30.4l11.9,29.8c20.7-9.9,39.8-22.6,56.9-37.6L397,419.6z M115,92.4 c13.9-12,29.4-22.3,46.1-30.4l-11.9-29.8c-20.7,9.9-39.8,22.6-56.8,37.6L115,92.4z M447.7,355.5c-7.8,14.9-17.2,28.8-28.1,41.5 l22.7,22.7c13.7-15.6,25.5-32.9,34.9-51.5L447.7,355.5z M471.4,272c-1.4,18.8-5.2,37-11.1,54.1l29.5,12.6 c7.5-21.1,12.2-43.5,13.6-66.8H471.4z M321.2,462c-15.7,5-32.2,8.2-49.2,9.4v32.1c21.2-1.4,41.7-5.4,61.1-11.7L321.2,462z M240,471.4c-18.8-1.4-37-5.2-54.1-11.1l-12.6,29.5c21.1,7.5,43.5,12.2,66 Line truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+14
View File
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="module" crossorigin src="/assets/index-CPLpx4lq.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-21nzev1V.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript'
],
parserOptions: {
ecmaVersion: 'latest'
}
}
+30
View File
@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
+45
View File
@@ -0,0 +1,45 @@
# ReJeobeardy
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Run Unit Tests with [Vitest](https://vitest.dev/)
```sh
npm run test:unit
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />
+13
View File
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+6807
View File
File diff suppressed because it is too large. Load diff
+50
View File
@@ -0,0 +1,50 @@
{
"name": "rejeobeardy",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@popperjs/core": "^2.11.8",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"axios": "^1.7.2",
"bootstrap": "^5.3.3",
"pinia": "^2.1.7",
"vue": "^3.4.21",
"vue-i18n": "^9.13.1",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
"@tsconfig/node20": "^20.1.4",
"@types/bootstrap": "^5.2.10",
"@types/jsdom": "^21.1.6",
"@types/node": "^20.12.5",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/test-utils": "^2.4.5",
"@vue/tsconfig": "^0.5.1",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"jsdom": "^24.0.0",
"npm-run-all2": "^6.1.2",
"sass": "^1.77.6",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vite-plugin-vue-devtools": "^7.0.25",
"vitest": "^1.4.0",
"vue-tsc": "^2.0.11"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+37
View File
@@ -0,0 +1,37 @@
<script setup lang="ts">
import { RouterView } from 'vue-router';
import NavBar from '@/components/blocks/NavBar.vue';
import FooterBlock from '@/components/blocks/FooterBlock.vue';
import GenericInfoModal from '@/components/modals/GenericInfoModal.vue';
import { provide, ref } from 'vue';
import { infoModalShowFnKey } from './services/UtilService';
const infoModal = ref<InstanceType<typeof GenericInfoModal> | null>(null);
function showInfoModal(title: string, text: string): void{
if( infoModal.value ){
infoModal.value.modalTitle = title;
infoModal.value.modalText = text;
infoModal.value.show();
} else {
console.error('Modal not yet available');
}
}
provide(infoModalShowFnKey, showInfoModal);
</script>
<template>
<div class="vh-100 overflow-y-scroll overflow-x-hidden">
<NavBar />
<RouterView />
<!-- <FooterBlock /> -->
<GenericInfoModal
ref="infoModal"
/>
</div>
</template>
+8
View File
@@ -0,0 +1,8 @@
const { VITE_API_BASE_URL, ...otherViteConfig } = import.meta.env;
export const ENV = {
API_BASE_URL: VITE_API_BASE_URL as string,
__vite__: otherViteConfig,
};
console.debug(ENV);
+3
View File
@@ -0,0 +1,3 @@
.preserve-breaks {
white-space: preserve-breaks;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg1"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
sodipodi:docname="PFP_BearHead.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showguides="true"
inkscape:zoom="0.7071068"
inkscape:cx="48.790367"
inkscape:cy="195.16147"
inkscape:window-width="1920"
inkscape:window-height="1008"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs1" />
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"
transform="translate(0.01884618,-0.22140619)">
<ellipse
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.42699;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="ellipse9"
ry="13.127905"
rx="11.039931"
cy="-10.383468"
cx="-78.467972"
transform="matrix(-0.88593467,-0.46381003,-0.43331387,0.90124309,0,0)" />
<ellipse
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.42699;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="ellipse8"
ry="13.127905"
rx="11.039931"
cy="36.007061"
cx="11.674847"
transform="matrix(0.88593467,-0.46381003,0.43331387,0.90124309,0,0)" />
<circle
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-dasharray:none;stroke-opacity:1"
id="path2"
cx="50.009468"
cy="51.98246"
r="34.316185" />
<path
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-dasharray:none;stroke-opacity:1"
d="m 43.246556,57.420114 c 0.75711,-2.163936 4.470201,-2.158401 6.762761,-2.158401 2.292561,0 6.005093,-0.0054 6.762762,2.158401 1.136946,3.246879 -3.319062,8.093347 -6.759248,8.094232 -3.441721,8.75e-4 -7.902893,-4.845611 -6.766275,-8.094232 z"
id="path5"
sodipodi:nodetypes="sssss" />
<path
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 49.984077,65.567745 c 0,4.590286 -0.329314,5.259871 -1.868084,6.148279 -2.521632,1.455864 -5.237785,-0.51905 -6.274968,-1.11787"
id="path6"
sodipodi:nodetypes="ccc" />
<path
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 49.938836,65.567745 c 0,4.590286 0.329314,5.259871 1.868083,6.148279 2.521632,1.455864 5.237784,-0.51905 6.274969,-1.11787"
id="path7"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 59.773948,42.208084 4.779484,-4.779484 4.778202,4.778204"
id="path9" />
<path
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 29.729393,42.208084 4.779485,-4.779484 4.778201,4.778204"
id="path10" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

@@ -0,0 +1,113 @@
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "bootstrap/scss/functions";
// 2. Include any default variable overrides here
/* Colors */
//Accents
$cyclamen: #e86a92ff;
$light-coral: #eb8a90ff;
$jungle-green: #419d78ff;
$celestial-blue: #3e92ccff;
$raisin-black: #161925ff;
$delft-blue: #23395bff;
$ucla-blue: #406e8eff;
$powder-blue: #8ea8c3ff;
$mint-green: #cbf7edff;
$space-cadet: #2b2d42ff;
$cool-gray: #8d99aeff;
$anti-flash-white: #edf2f4ff;
$rich-black: #2d3543;
/* Variable definitions */
$primary-accent: $cyclamen;
$primary-accent-dark: $cyclamen;
$secondary-accent: $celestial-blue;
$secondary-accent-dark: $celestial-blue;
// $secondary-accent: $jungle-green;
// $secondary-accent-dark: $jungle-green;
/* Bootstrap Colors overrides */
$primary: $primary-accent;
$secondary: $secondary-accent;
// $success: $green;
// $info: $cyan;
// $warning: $yellow;
// $danger: $red;
$light: $anti-flash-white;
$light-accented: shade-color($anti-flash-white, 10%);
$dark: $space-cadet;
$dark-accented: shade-color($space-cadet, 15%);
/* Bootstrap Variable overrides */
$body-bg-dark: $space-cadet;
$body-secondary-bg-dark: $dark-accented;
$body-bg: $anti-flash-white;
$body-secondary-bg: $light-accented;
// $font-size-base: 1.5rem;
// 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets)
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
// $navbar-dark-active-color: $primary;
// $navbar-light-active-color: $primary;
/* Bootstrap Color Map adjustments */
$custom-colors: (
"gray": $gray-500,
"dark-accented": $dark-accented,
"rich-black": $rich-black,
);
$theme-colors: map-merge($theme-colors, $custom-colors);
// 4. Include any default map overrides here
// 5. Include remainder of required parts
@import "bootstrap/scss/bootstrap";
// @import "bootstrap/scss/maps";
// @import "bootstrap/scss/mixins";
// @import "bootstrap/scss/root";
// 6. Optionally include any other parts as needed
@import "bootstrap/scss/utilities";
// @import "bootstrap/scss/reboot";
// @import "bootstrap/scss/type";
// @import "bootstrap/scss/images";
// @import "bootstrap/scss/containers";
// @import "bootstrap/scss/grid";
// @import "bootstrap/scss/helpers";
$utilities: map-merge(
$utilities,
(
"width": map-merge(
map-get($utilities, "width"),
(
values: map-merge(
map-get(map-get($utilities, "width"), "values"),
(fit-content: fit-content),
),
),
),
)
);
// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "bootstrap/scss/utilities/api";
// 8. Add additional custom code here
@import "./exotic_theme.scss";
@import "bootstrap/scss/bootstrap";
@import "../css/main.css";
@@ -0,0 +1,23 @@
[data-bs-theme="blue"] {
--bs-body-color: var(--bs-pink);
--bs-body-color-rgb: #{to-rgb($white)};
--bs-body-bg: var(--bs-white);
--bs-body-bg-rgb: #{to-rgb($blue)};
--bs-tertiary-bg: #{$blue-600};
.dropdown-menu {
--bs-dropdown-bg: #{mix($blue-500, $blue-600)};
--bs-dropdown-link-active-bg: #{$blue-700};
}
.btn-secondary {
--bs-btn-bg: #{mix($gray-600, $blue-400, .5)};
--bs-btn-border-color: #{rgba($white, .25)};
--bs-btn-hover-bg: #{darken(mix($gray-600, $blue-400, .5), 5%)};
--bs-btn-hover-border-color: #{rgba($white, .25)};
--bs-btn-active-bg: #{darken(mix($gray-600, $blue-400, .5), 10%)};
--bs-btn-active-border-color: #{rgba($white, .5)};
--bs-btn-focus-border-color: #{rgba($white, .5)};
--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(255, 255, 255, .2);
}
}
@@ -0,0 +1,14 @@
// import { describe, it, expect } from 'vitest'
// import { mount } from '@vue/test-utils'
// import HelloWorld from '../HelloWorld.vue'
// describe('HelloWorld', () => {
// it('renders properly', () => {
// const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
// expect(wrapper.text()).toContain('Hello Vitest')
// })
// })
// Test Example
@@ -0,0 +1,48 @@
<script setup lang="ts">
import { ref } from 'vue';
const boards = ref([{
id: 1,
boardName: "mockBoard",
},{
id: 2,
boardName: "test Mock",
},{
id: 3,
boardName: "Mocka Board",
},{
id: 4,
boardName: "Mocka Board 2",
}]);
</script>
<template>
<div class="row">
<template v-for="board in boards" :key="board.id">
<div class="col-4 mb-3">
<div class="card">
<div class="card-header">
{{ board.boardName }}
</div>
<div class="card-body">
<div class="row">
<div class="col">
<div class="d-flex justify-content-around align-items-center">
<button class="btn btn-sm btn-primary">
<font-awesome-icon :icon="['fas', 'edit']" />
Edit
</button>
<button class="btn btn-sm btn-primary">
<font-awesome-icon :icon="['fas', 'play']" />
Play
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</div>
</template>
@@ -0,0 +1,23 @@
<script setup lang="ts">
import LocaleChanger from '@/components/blocks/LocaleChanger.vue';
import ThemeChanger from '@/components/blocks/ThemeChanger.vue';
import IconJeobeardy from '@/components/icons/IconJeobeardy.vue';
</script>
<template>
<div class="container-fluid bg-body-secondary p-3 position-absolute bottom-0">
<div class="container d-flex align-content-center justify-content-around">
<div class="d-flex gap-2">
<LocaleChanger />
<ThemeChanger />
</div>
<div>
<IconJeobeardy height="2rem" width="4rem"/>
</div>
</div>
</div>
</template>
@@ -0,0 +1,38 @@
<script setup lang="ts">
import { onMounted, watch } from 'vue';
import { useI18n } from 'vue-i18n';
const localeLocalStorageKey = 'locale';
const i18n = useI18n();
onMounted( () => {
const initialLocale = localStorage.getItem( localeLocalStorageKey );
if( initialLocale !== null ) {
i18n.locale.value = initialLocale;
}
} );
watch(
() => i18n.locale.value,
( newVal ) => {
localStorage.setItem( localeLocalStorageKey, newVal );
}
);
</script>
<template>
<div class="dropdown">
<button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ $t( `i18n.${$i18n.locale}.name` ) }}
</button>
<ul class="dropdown-menu">
<li v-for=" locale in $i18n.availableLocales " :key="`locale-${locale}`" @click="$i18n.locale = locale"
role="button">
<a class="dropdown-item pointer" :class="[{ active: $i18n.locale === locale }]">
{{ $t( `i18n.${locale}.name` ) }}
</a>
</li>
</ul>
</div>
</template>
@@ -0,0 +1,75 @@
<script setup lang="ts">
import { RouterLink, useRoute } from 'vue-router';
import IconJeobeardy from '@/components/icons/IconJeobeardy.vue';
import ThemeChanger from './ThemeChanger.vue';
import LocaleChanger from './LocaleChanger.vue';
import { useUserStore } from '@/stores/UserStore';
const navNames = {
HOME: "home",
ABOUT: "about",
}
const route = useRoute();
const userStore = useUserStore();
const isActiveNav = ( navName: string ) => {
switch( navName ){
default:
case navNames.HOME:
return route.name === "home";
case navNames.ABOUT:
return route.name === "about";
}
}
</script>
<template>
<nav class="navbar navbar-expand-lg bg-dark-accented">
<div class="container px-5">
<div class="position-absolute start-0 top-50 translate-middle-y d-flex ms-3 gap-3">
<ThemeChanger />
<LocaleChanger />
</div>
<a class="navbar-brand rounded rounded-circle d-block d-lg-none" href="#">
<IconJeobeardy height="3.5rem" width="3.5rem" />
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mb-2 mb-lg-0 d-flex align-items-center justify-content-center w-100">
<li class="nav-item">
<RouterLink to="/" class="nav-link text-light fs-3" :class="[{active: isActiveNav(navNames.HOME)}]" :aria-current="isActiveNav(navNames.HOME) ? 'page' : false">{{ $t( 'nav.home' ) }}</RouterLink>
</li>
<li class="nav-item px-5 mx-5 rounded-5 py-2">
<RouterLink to="/" class="nav-link py-0">
<IconJeobeardy height="3rem" width="4rem"/>
</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/about" class="nav-link text-light fs-3" :class="[{active: isActiveNav(navNames.ABOUT)}]" :aria-current="isActiveNav(navNames.HOME) ? 'page' : false">{{ $t( 'nav.about' ) }}</RouterLink>
</li>
</ul>
</div>
<div class="position-absolute end-0 top-50 translate-middle-y d-flex me-3">
<div v-if="userStore.loggedIn">
{{ userStore.getUserOutput }}
</div>
<div v-else>
<RouterLink to="/login" class="btn btn-sm btn-outline-primary">
Login
</RouterLink>
</div>
</div>
</div>
</nav>
</template>
@@ -0,0 +1,25 @@
<script setup lang="ts">
import { useBootstrapTheme } from '@/composables/colorTheme';
const { availableThemes, currentTheme } = useBootstrapTheme();
</script>
<template>
<div class="theme-changer">
<div class="dropdown">
<button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<FontAwesomeIcon :icon="currentTheme.icon" />
{{ $t( currentTheme.name ) }}
</button>
<ul class="dropdown-menu">
<li v-for="theme in availableThemes" :key="`theme-${theme.bsName}`" @click="currentTheme = theme" role="button">
<a class="dropdown-item pointer" :class="[{active: theme.bsName === currentTheme.bsName}]">
<FontAwesomeIcon :icon="theme.icon" />
{{ $t(theme.name) }}
</a>
</li>
</ul>
</div>
</div>
</template>
@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>
@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>
@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>
@@ -0,0 +1,38 @@
<script setup lang="ts">
interface Props {
height?: string,
width?: string,
bearColor?: string,
questionmarkColor?: string,
}
const props = withDefaults(defineProps<Props>(), {
bearColor: '#e86a92ff',
questionmarkColor: '#ffffff',
})
</script>
<template>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg :style="[{height: props.height}, {width: props.width}]" width="103.44236mm" height="80.726883mm" viewBox="0 0 103.44236 80.726882" version="1.1" id="svg5"
xml:space="preserve" inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="jeobeardy_logo_min.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs id="defs2" />
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-51.241626,-83.781469)">
<path
:style="`opacity:1;fill:${props.bearColor};fill-opacity:1;stroke:${props.bearColor};stroke-width:5;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers`"
d="m 89.597943,161.46239 c 4.957603,-11.31418 10.365454,-13.95841 18.872727,-16.46612 l -0.969,2.23271 10.17543,-3.72589 -1.44748,2.89495 c 7.77057,-2.08212 9.96019,-3.12838 17.29351,-0.22855 8.26326,-4.46932 15.33088,-3.99272 18.58862,-16.15077 0.39797,-1.48523 0.47248,-3.46705 -16.76023,-13.25582 0.6718,-1.59948 -0.64483,-6.30424 -1.44747,-7.69446 -11.87841,-11.878406 -22.82609,-9.786559 -25.14034,-11.122693 -5.10133,-2.945257 -5.77849,-9.894901 -10.741782,-10.89415 -6.64933,-1.781683 -10.639666,-0.422382 -8.015124,7.302597 -4.755054,-0.07748 -19.311199,0.225543 -19.311199,0.225543 l 4.218975,2.479364 -10.418322,0.541411 4.479459,2.526958 c -6.00567,0.93796 -10.085508,3.02646 -13.849528,6.19633 l 3.879167,3.25675 c 11.896264,-8.5256 27.407274,-7.5637 31.986403,1.85066 8.053096,14.19441 -5.364775,20.05902 -11.44594,30.07143 1.070396,5.80331 1.412146,7.38337 3.627235,11.42304 1.414891,2.45066 5.193343,11.34733 6.424889,8.53671 z"
id="path919" sodipodi:nodetypes="sccccccccccccccccccccs" />
<path
:style="`opacity:1;fill:none;stroke:${props.questionmarkColor};stroke-width:8;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1`"
d="m 57.671788,111.83817 c 4.776043,-5.45079 12.940609,-7.24498 19.118918,-7.24498 13.656487,0 13.875779,8.51413 14.475615,10.75275 0,14.09963 -13.925936,15.13618 -10.506511,27.69217 0.653123,2.43749 0.932727,3.34729 2.242618,6.17334"
id="path2566" sodipodi:nodetypes="ccccc" />
<ellipse
:style="`opacity:1;fill:${props.questionmarkColor};fill-opacity:1;stroke:${props.questionmarkColor};stroke-width:2.80661;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1`"
id="path2620" cy="182.73756" cx="-0.050881278" rx="3.2998796" ry="3.4343019" transform="rotate(-29.11515)" />
</g>
</svg>
</template>
@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>
@@ -0,0 +1,19 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>
@@ -0,0 +1,66 @@
<script setup lang="ts">
import { Modal } from 'bootstrap';
import { onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const modalRef = ref<null | Element>(null);
let modalInstance: null | Modal;
onMounted( () => {
modalInstance = Modal.getOrCreateInstance(modalRef.value as Element);
});
onUnmounted( () => {
modalInstance?.dispose();
});
function show(){
if( modalInstance ){
modalInstance.show();
} else {
console.error("Modal was not properly created before showing");
}
}
function hide(){
if( modalInstance ){
modalInstance.hide();
} else {
console.error("Modal was not properly created before hiding");
}
}
const modalText = ref('');
const modalTitle = ref('');
const modalId = ref('');
defineExpose({
show,
hide,
modalText,
modalTitle,
modalId,
});
</script>
<template>
<div class="modal" tabindex="-1" ref="modalRef" :id="modalId">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ modalTitle }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body preserve-breaks">
<p>{{ modalText }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">{{ t("common.buttons.close") }}</button>
</div>
</div>
</div>
</div>
</template>
@@ -0,0 +1,12 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
<template>
<div>
{{ t( 'about.whatis' ) }}
</div>
</template>
@@ -0,0 +1,12 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
<template>
<div>
{{ t( 'about.whatis' ) }}
</div>
</template>
@@ -0,0 +1,123 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { userService } from '@/services/UserService';
import IconJeobeardy from '../icons/IconJeobeardy.vue';
const testResponse = ref( {} );
onMounted( () => {
userService.getTest( 'ping', '42' )
.then( ( response: any ) => {
testResponse.value = response.data;
} );
} );
</script>
<template>
<div class="row">
<div class="col">
<div class="w-100 d-flex justify-content-center my-5">
<h1>
{{ $t( 'home.welcome' ) }}
{{ testResponse }}
</h1>
</div>
</div>
</div>
<div
class="container-fluid px-0 d-flex justify-content-center align-items-center flex-column">
<div class="row w-100 border-top">
<div class="col-md-6 col-12 px-0 bg-body-secondary">
<div class="d-flex justify-content-center align-items-center h-100 w-100 flex-column">
<h3 class="m-1">
{{ $t("join.text") }}
</h3>
<p>
{{ $t("join.alreadyHostedGome") }}
</p>
<p>
{{ $t("join.textCode") }}
</p>
<div class="row">
<div class="col-auto">
<input type="text" class="form-control" placeholder="Code">
</div>
<div class="col-auto">
<button class="btn btn-primary">{{ $t("join.button") }}</button>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-12 px-0 mx-0">
<img class="w-100" src="/src/assets/images/OldInGameBlurredRotated.jpeg"
alt="Blurred, slightly tilted image of how the game looks like">
</div>
</div>
<div class="row w-100 border-bottom">
<div class="col-md-6 col-12 px-0 mx-0">
<img class="w-100" src="/src/assets/images/OldInGameBlurredRotated.jpeg"
alt="Blurred, slightly tilted image of how the game looks like">
</div>
<div class="col-md-6 col-12 px-0 mx-0 bg-body-secondary">
<div class="h-100 w-100 d-flex justify-content-center align-items-center flex-column">
<h3 class="m-1">
{{ $t("host.text") }}
</h3>
<p>
{{ $t("host.alreadyHostedGome") }}
</p>
<p>
{{ $t("host.textCode") }}
</p>
<div class="row">
<div class="col-auto">
<input type="text" class="form-control" placeholder="Code">
</div>
<div class="col-auto">
<button class="btn btn-primary">{{ $t("host.button") }}</button>
</div>
</div>
</div>
</div>
</div>
<div class="row w-100">
<div class="col mt-5 mb-5">
<div class="container mb-5 text-center">
<h4>
How does it work?
</h4>
<div class="row mt-5">
<div class="col-4 d-flex justify-content-center align-items-center flex-column gap-3">
<div class="border rounded-circle w-fit-content">
<IconJeobeardy height="2rem" width="2rem" />
</div>
Create a Board
</div>
<div class="col-4 d-flex justify-content-center align-items-center flex-column gap-3">
<div class="border rounded-circle w-fit-content">
<IconJeobeardy height="2rem" width="2rem" />
</div>
Invite your friends
</div>
<div class="col-4 d-flex justify-content-center align-items-center flex-column gap-3">
<div class="border rounded-circle w-fit-content">
<IconJeobeardy height="2rem" width="2rem" />
</div>
Have fun playing
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.home-player-join-row {
background-image: url("/src/assets/images/OldInGameBlurredRotated.jpeg");
background-repeat: no-repeat;
background-size: cover;
}
</style>
@@ -0,0 +1,113 @@
<script setup lang="ts">
import type { LoginDto } from '@/models/dto/LoginDto';
import type { User } from '@/models/user/User';
import { authService } from '@/services/AuthService';
import { infoModalShowFnKey } from '@/services/UtilService';
import { useUserStore } from '@/stores/UserStore';
import useVuelidate from '@vuelidate/core';
import { createI18nMessage, required } from '@vuelidate/validators';
import { computed, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { RouterLink, useRouter } from 'vue-router';
const { t } = useI18n();
const router = useRouter();
const userStore = useUserStore();
const showInfoModal = inject(infoModalShowFnKey);
const username = ref('');
const password = ref('');
const errorMessage = ref('');
const loginInProgress = ref(false);
function loginUser(){
v$.value.$touch();
if(v$.value.$error){
errorMessage.value = t('forms.validate-fields');
setTimeout(() => {
errorMessage.value = '';
}, 3000);
return;
} else {
errorMessage.value = '';
}
const loginDto: LoginDto = { username: username.value, password: password.value };
loginInProgress.value = true;
authService.loginUser( loginDto )
.then( ( response ) => {
userStore.setUser(response as User);
router.push({ name: 'profile'});
})
.catch( ( err ) => {
console.error(err);
const modalText = t('login.error.process');
if( showInfoModal !== undefined ){
showInfoModal(t('common.error.generic'), modalText);
} else {
alert(modalText);
}
})
.finally( () => {
loginInProgress.value = false;
})
}
const withI18nMessage = createI18nMessage({t: t});
const inputRequired = withI18nMessage(required);
const rules = computed( () => ({
username: { inputRequired },
password: { inputRequired },
}));
const v$ = useVuelidate(rules, { username, password });
</script>
<template>
<div class="container d-flex flex-column justify-content-center align-items-center">
<div class="row mt-5">
<div class="col">
<div class="card">
<div class="card-header bg-primary p-4">
<h2 class="mb-0">
{{ t( 'login.loginHeader' ) }}
</h2>
</div>
<div class="card-body bg-body-secondary">
<div class="d-flex flex-column gap-3 mt-3">
<div class="mb-3">
<label for="input-username">
{{ t( 'login.username' ) }}
<span v-if="v$.username.$error" class="text-danger ps-3">
{{ v$.username.$errors[0].$message }}
</span></label>
<input v-model="username" type="text" id="input-username" class="form-control" :class="[{'border-danger': v$.username.$error}]" @blur="v$.username.$touch">
</div>
<div class="mb-3">
<label for="input-username">
{{ t( 'login.password' ) }}
<span v-if="v$.password.$error" class="text-danger ps-3">
{{ v$.password.$errors[0].$message }}
</span>
</label>
<input v-model="password" type="password" id="input-username" class="form-control" :class="[{'border-danger': v$.password.$error}]" @blur="v$.password.$touch">
</div>
<div class="mb-3 d-flex justify-content-between">
<RouterLink to="/signup" class="btn btn-outline-primary">
{{ t( "login.signupLinkButton" ) }}
</RouterLink>
<button class="btn btn-primary" @click="loginUser">
{{ t( "login.loginButton" ) }}
</button>
</div>
<div v-if="errorMessage" class="alert alert-danger" role="alert">{{ errorMessage }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
@@ -0,0 +1,47 @@
<script setup lang="ts">
import { useUserStore } from '@/stores/UserStore';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import BoardSelector from '@/components/blocks/BoardSelector.vue';
const { t } = useI18n();
const userStore = useUserStore();
const pfpSource = computed( () => {
return ( userStore.profilePicture === null ? "/src/assets/images/PFP_BearHead.svg" : userStore.profilePicture )
})
</script>
<template>
<div class="d-flex flex-column justify-content-center align-items-center mt-5">
<h1>
{{ $t('profile.yourProfile') }}
</h1>
<div class="ratio ratio-1x1 border rounded-5" style="width: 15rem;">
<img :src="pfpSource" alt="Your Profile Picture" />
</div>
<p class="fs-3">
{{ userStore.username }}
</p>
<div class="row bg-body-secondary w-100 py-4">
<div class="col text-center">
<h2>
{{ $t('profile.yourBoards') }}
</h2>
<div class="container">
<BoardSelector />
</div>
</div>
</div>
<div class="row w-100 py-4 mb-5">
<div class="col text-center">
<h2>
{{ $t('settings.heading') }}
</h2>
<button class="btn btn-outline-primary">{{ $t('profile.gotoSettings') }}</button>
</div>
</div>
</div>
</template>
@@ -0,0 +1,126 @@
<script setup lang="ts">
import { type LoginDto } from '@/models/dto/LoginDto';
import type { User } from '@/models/user/User';
import { authService } from '@/services/AuthService';
import { infoModalShowFnKey } from '@/services/UtilService';
import { useUserStore } from '@/stores/UserStore';
import useVuelidate from '@vuelidate/core';
import { createI18nMessage, minLength, required, sameAs } from '@vuelidate/validators';
import { computed, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { RouterLink, useRouter } from 'vue-router';
const { t } = useI18n();
const router = useRouter();
const userStore = useUserStore();
const showInfoModal = inject(infoModalShowFnKey);
const username = ref('');
const password = ref('');
const passwordRepeat = ref('');
const errorMessage = ref('');
const signupInProgress = ref(false);
function signupUser(){
v$.value.$touch();
if(v$.value.$error){
errorMessage.value = t('forms.validate-fields');
setTimeout(() => {
errorMessage.value = '';
}, 3000);
return;
} else {
errorMessage.value = '';
}
const signupDto: LoginDto = { username: username.value, password: password.value };
signupInProgress.value = true;
authService.signupUser( signupDto )
.then( ( response ) => {
userStore.setUser(response as User);
router.push({ name: 'profile'});
})
.catch( ( err ) => {
console.error(err);
const modalText = t('signup.error.process');
if( showInfoModal !== undefined ){
showInfoModal(t('common.error.generic'), modalText);
} else {
alert(modalText);
}
})
.finally( () => {
signupInProgress.value = false;
})
}
const withI18nMessage = createI18nMessage({t: t});
const inputRequired = withI18nMessage(required);
const rules = computed( () => ({
username: { inputRequired },
password: { inputRequired, minLength: withI18nMessage(minLength(10)) },
passwordRepeat: { inputRequired, sameAs: withI18nMessage(sameAs(password.value, t('login.password'))) },
}));
const v$ = useVuelidate(rules, { username, password, passwordRepeat });
</script>
<template>
<div class="container d-flex flex-column justify-content-center align-items-center">
<div class="row mt-5">
<div class="col">
<div class="card">
<div class="card-header bg-primary p-4">
<h2 class="mb-0">
{{ t( 'signup.signupHeader' ) }}
</h2>
</div>
<div class="card-body bg-body-secondary">
<div class="d-flex flex-column gap-3 mt-3">
<div class="mb-3">
<label for="input-username">
{{ t( 'login.username' ) }}
<span v-if="v$.username.$error" class="text-danger ps-3">
{{ v$.username.$errors[0].$message }}
</span>
</label>
<input type="text" id="input-username" class="form-control" :class="[{'border-danger': v$.username.$error}]" v-model="username" @blur="v$.username.$touch">
</div>
<div class="mb-3">
<label for="input-username">
{{ t( 'login.password' ) }}
<span v-if="v$.password.$error" class="text-danger ps-3">
{{ v$.password.$errors[0].$message }}
</span>
</label>
<input type="password" id="input-username" class="form-control" :class="[{'border-danger': v$.password.$error}]" v-model="password" @blur="v$.password.$touch">
</div>
<div class="mb-3">
<label for="input-username-repeat">
{{ t( 'signup.password-repeat' ) }}
<span v-if="v$.passwordRepeat.$error" class="text-danger ps-3">
{{ v$.passwordRepeat.$errors[0].$message }}
</span>
</label>
<input type="password" id="input-username-repeat" class="form-control" :class="[{'border-danger': v$.passwordRepeat.$error}]" v-model="passwordRepeat" @blur="v$.passwordRepeat.$touch">
</div>
<div class="mb-3 d-flex justify-content-between">
<RouterLink to="/login" class="btn btn-outline-primary">
{{ t( "signup.loginLinkButton" ) }}
</RouterLink>
<button class="btn btn-primary" @click="signupUser" :disabled="signupInProgress">
<font-awesome-icon v-if="signupInProgress" :icon="['fas', 'spinner']" spin/>
{{ t( "signup.signupButton" ) }}
</button>
</div>
<div v-if="errorMessage" class="alert alert-danger" role="alert">{{ errorMessage }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
@@ -0,0 +1,57 @@
import { onMounted, ref, watch } from "vue";
const localStorageKey = "theme";
const darkTheme = {
bsName: "dark",
name: "theme.dark.name",
icon: ["fas", "moon"],
};
const lightTheme = {
bsName: "light",
name: "theme.light.name",
icon: ["fas", "sun"],
};
const highContrastTheme = {
bsName: "high-contrast",
name: "theme.high-contrast.name",
icon: ["fas", "circle-half-stroke"],
};
export function useBootstrapTheme() {
const availableThemes = ref( [
darkTheme,
lightTheme,
highContrastTheme,
] );
onMounted( () => {
let initialThemeBsName: string | null = localStorage.getItem( localStorageKey );
if( initialThemeBsName == null ) {
localStorage.setItem( localStorageKey, "dark" );
initialThemeBsName = "dark";
}
const initialTheme = availableThemes.value.findIndex( theme => theme.bsName === initialThemeBsName );
if( initialTheme !== -1 ) {
currentTheme.value = availableThemes.value[initialTheme];
}
const htmlElem = document.getElementsByTagName( 'html' );
htmlElem[0].dataset.bsTheme = currentTheme.value.bsName;
} );
const currentTheme = ref( darkTheme );
watch(
currentTheme,
( newVal ) => {
document.getElementsByTagName( 'html' )[0].dataset.bsTheme = newVal.bsName;
localStorage.setItem( localStorageKey, newVal.bsName );
}
);
return {
availableThemes,
currentTheme,
};
}
+38
View File
@@ -0,0 +1,38 @@
{
"home": {
"welcome": "Willkommen bei Jeobeardy!"
},
"about": {
"whatis": "Was ist Jeobeardy?"
},
"login": {
"loginHeader": "Logge dich mit deinem Jeobeardy Konto ein",
"username": "Benutzername",
"password": "Passwort"
},
"theme": {
"dark": {
"name": "Dunkel"
},
"light": {
"name": "Hell"
},
"high-contrast": {
"name": "Hoher Kontrast"
}
},
"i18n": {
"en": {
"name": "Englisch",
"shortName": "en"
},
"de": {
"name": "Deutsch",
"shortName": "de"
}
},
"nav": {
"home": "Home",
"about": "Über"
}
}
+90
View File
@@ -0,0 +1,90 @@
{
"home": {
"welcome": "Welcome to Jeobeardy!"
},
"about": {
"whatis": "What is Jeobeardy?"
},
"login": {
"loginHeader": "Login to your Jeobeardy Account",
"loginButton": "Login",
"signupLinkButton": "Sign up",
"username": "Username",
"password": "Password",
"error": {
"process": "An error occured during the login process"
}
},
"signup": {
"signupHeader": "Create a new Jeobeardy Account",
"signupButton": "Sign Up",
"loginLinkButton": "Back to Login",
"password-repeat": "Repeat Password",
"password-not-conform": "The password does not meet the required criteria",
"password-criteria-length": "The password needs to be at least 10 characters long",
"error": {
"process": "An error occured during the signup process"
}
},
"forms": {
"validate-fields": "Make sure that all fields are valid"
},
"validations": {
"inputRequired": "This field is required",
"minLength": "Minimum of {min} characters required",
"sameAs": "Must match {otherName}"
},
"profile": {
"yourProfile": "Your Profile",
"yourBoards": "Your Boards",
"gotoSettings": "Go to Settings"
},
"settings": {
"heading": "Settings"
},
"common": {
"buttons": {
"close": "Close"
},
"error": {
"generic": "Error"
}
},
"join": {
"button": "Join",
"text": "Join a Game",
"alreadyHostedGome": "Someone else is already hosting a game?",
"textCode": "Enter the code you get from your host and join the lobby."
},
"host": {
"button": "Host",
"text": "Host a Game",
"alreadyHostedGome": "Wanna create a board and host a game yourself?",
"textCode": "Wanna create a board and host a game yourself?"
},
"theme": {
"dark": {
"name": "Dark"
},
"light": {
"name": "Light"
},
"highContrast": {
"name": "High Contrast"
}
},
"i18n": {
"en": {
"name": "English",
"shortName": "en"
},
"de": {
"name": "German",
"shortName": "de"
}
},
"nav": {
"home": "Home",
"about": "About"
}
}
+47
View File
@@ -0,0 +1,47 @@
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import { createI18n } from 'vue-i18n';
import App from './App.vue';
import router from './router';
import '@/assets/scss/customized_bootstrap.scss';
// Importing bootstrap components which rely on js here
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Dropdown } from 'bootstrap';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faSun, faMoon, faCircleHalfStroke, faEdit, faPlay, faSpinner } from '@fortawesome/free-solid-svg-icons';
import enMessages from './locales/en.json';
import deMessages from './locales/de.json';
const i18n = createI18n( {
legacy: false,
locale: 'en',
fallbackLocale: 'en',
messages: {
en: enMessages,
de: deMessages,
}
} );
library.add(
faSun,
faMoon,
faCircleHalfStroke,
faEdit,
faPlay,
faSpinner
)
const app = createApp( App );
app.use( createPinia() );
app.component( 'FontAwesomeIcon', FontAwesomeIcon );
app.use( router );
app.use( i18n );
app.mount( '#app' );
@@ -0,0 +1,14 @@
// export class LoginDto{
// username: String;
// password: String;
// constructor(username: String, password: String){
// this.username = username;
// this.password = password;
// }
// }
export type LoginDto = {
username: String;
password: String;
}
+5
View File
@@ -0,0 +1,5 @@
export type User = {
username: string,
password: string,
profilePictureFilename: string | undefined,
}
+53
View File
@@ -0,0 +1,53 @@
import { createRouter, createWebHistory } from 'vue-router';
import HomePage from '@/components/pages/HomePage.vue';
import AboutPage from '@/components/pages/AboutPage.vue';
import LoginPage from '@/components/pages/LoginPage.vue';
import SignupPage from '@/components/pages/SignupPage.vue';
import GamePage from '@/components/pages/GamePage.vue';
import ProfilePage from '@/components/pages/ProfilePage.vue';
const router = createRouter( {
history: createWebHistory( import.meta.env.BASE_URL ),
routes: [
{
path: '/',
name: 'home',
component: HomePage,
},
{
path: '/about',
name: 'about',
component: AboutPage,
},
{
path: '/login',
name: 'login',
component: LoginPage,
},
{
path: '/signup',
name: 'signup',
component: SignupPage,
},
{
path: '/profile',
name: 'profile',
component: ProfilePage,
},
{
path: '/game',
name: 'Game',
component: GamePage,
},
// {
// path: '/about',
// name: 'about',
// // route level code-splitting
// // this generates a separate chunk (About.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import('../views/AboutView.vue')
// }
]
} );
export default router;
@@ -0,0 +1,61 @@
import { ENV } from "@/Env";
import type { LoginDto } from '@/models/dto/LoginDto';
import axios from "axios";
class AuthService {
signupUser( signupDto: LoginDto ) {
return new Promise( ( resolve, reject ) => {
axios.post( `${ENV.API_BASE_URL}/auth/signup`,
signupDto,
{
withCredentials: true,
},
)
.then( ( response ) => {
resolve( response.data );
} )
.catch( ( error ) => {
reject( error );
} );
} );
}
loginUser( loginDto: LoginDto ) {
return new Promise( ( resolve, reject ) => {
axios.post( `${ENV.API_BASE_URL}/auth/login`,
loginDto,
{
withCredentials: true,
},
)
.then( ( response ) => {
resolve( response );
} )
.catch( ( error ) => {
reject( error );
} );
} );
}
logoutUser() {
return new Promise( ( resolve, reject ) => {
axios.post( `${ENV.API_BASE_URL}/auth/logout`,
null,
{
withCredentials: true,
},
)
.then( ( response ) => {
resolve( response );
} )
.catch( ( error ) => {
reject( error );
} );
} );
}
}
export const authService = new AuthService();
@@ -0,0 +1,26 @@
import { ENV } from "@/Env";
import axios from "axios";
class UserService {
getTest( pathVar: String, param: String ) {
return new Promise( ( resolve, reject ) => {
axios.get( `${ENV.API_BASE_URL}/user/test/${pathVar}`,
{
params: {
"param1": param,
},
withCredentials: true,
},
)
.then( ( response ) => {
resolve( response );
} )
.catch( ( error ) => {
reject( error );
} );
} );
}
}
export const userService = new UserService();
@@ -0,0 +1,8 @@
import type { InjectionKey } from 'vue';
class UtilService{
}
export const infoModalShowFnKey = Symbol() as InjectionKey<Function>;
+38
View File
@@ -0,0 +1,38 @@
import { computed, ref } from "vue";
import { defineStore } from "pinia";
import type { User } from '@/models/user/User';
export const useUserStore = defineStore( 'user', () => {
const username = ref( '' );
const profilePicture = ref<undefined | string>( undefined );
const loggedIn = ref(false);
const getUserOutput = computed(() => `${username.value}`);
function setUser(user: User){
username.value = user.username;
profilePicture.value = user.profilePictureFilename;
loggedIn.value = true;
sessionStorage.setItem() //???
}
function unsetUser(){
username.value = '';
profilePicture.value = undefined;
loggedIn.value = false;
}
return {
//Refs
username,
profilePicture,
loggedIn,
//Getters
getUserOutput,
//Functions
setUser,
unsetUser,
};
} );
+14
View File
@@ -0,0 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/**/*", "src/**/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
},
"resolveJsonModule": true,
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.vitest.json"
}
],
"compilerOptions": {
"module": "ES2022",
"moduleResolution": "Node",
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.app.json",
"exclude": [],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
"lib": [],
"types": ["node", "jsdom"]
}
}
+22
View File
@@ -0,0 +1,22 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueDevTools from 'vite-plugin-vue-devtools'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
VueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build:{
outDir: '../resources/static',
emptyOutDir: true,
}
});
+14
View File
@@ -0,0 +1,14 @@
import { fileURLToPath } from 'node:url'
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
import viteConfig from './vite.config'
export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: 'jsdom',
exclude: [...configDefaults.exclude, 'e2e/**'],
root: fileURLToPath(new URL('./', import.meta.url))
}
})
)