diff --git a/.gitignore b/.gitignore index 314044f5dc0ed57e196a32064f9e558a5e9e6463..dabc1102b9ba1d57d6506d7a61bccd54fecf4949 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,284 @@ -# Created by https://www.toptal.com/developers/gitignore/api/macos -# Edit at https://www.toptal.com/developers/gitignore?templates=macos +# Created by https://www.toptal.com/developers/gitignore/api/pycharm,flask +# Edit at https://www.toptal.com/developers/gitignore?templates=pycharm,flask + +### Flask ### +instance/* +!instance/.gitignore +.webassets-cache +.env + +### Flask.Python Stack ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml ### macOS ### # General @@ -34,4 +313,4 @@ Temporary Items # iCloud generated files *.icloud -# End of https://www.toptal.com/developers/gitignore/api/macos \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/pycharm,flask diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f9db4a565717bb3e78094e15b2b520c834566f9e..606273791c3804d1a9b8b1caa5aff1677b7233ab 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,11 +43,17 @@ stages: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" # Disables TLS so Docker client can talk to the daemon without TLS setup before_script: - - docker info + - echo "$DOCKER_HUB_TOKEN" | docker login $DOCKER_REGISTRY --username $DOCKER_REGISTRY_USER --password-stdin script: - cd ${CI_PROJECT_DIR} + - VERSION=$(cat VERSION.txt) + - docker build --file scripts/Dockerfile -t $DOCKER_REGISTRY_USER/beacon:latest -t $DOCKER_REGISTRY_USER/beacon:$VERSION . + - docker push $DOCKER_REGISTRY_USER/beacon:latest + - docker push $DOCKER_REGISTRY_USER/beacon:$VERSION + after_script: + - docker logout $DOCKER_REGISTRY rules: - - if: $CI_COMMIT_REF_PROTECTED == "true" + - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_COMMIT_REF_PROTECTED == "true" @@ -113,28 +119,6 @@ stages: junit: "${CI_PROJECT_DIR}/mods/common/build/test-results/test/TEST-*.xml" -"Test mod: Fabric": - stage: test - image: gradle:jdk21-alpine - tags: - - docker - dependencies: - - "Build mod: Fabric" - needs: - - job: "Build mod: Fabric" - script: - - cd ${CI_PROJECT_DIR}/mods/fabric - - ./gradlew test jacocoTestReport - - cat ${CI_PROJECT_DIR}/mods/fabric/build/reports/jacoco/test/html/index.html - coverage: /Total.*?([0-9]{1,3})%/ - artifacts: - reports: - coverage_report: - coverage_format: jacoco - path: ${CI_PROJECT_DIR}/mods/fabric/build/reports/jacoco/test/jacocoTestReport.xml - junit: "${CI_PROJECT_DIR}/mods/fabric/build/test-results/test/TEST-*.xml" - - "Upload: Mods": stage: deploy image: alpine/curl:latest diff --git a/README.md b/README.md index 6ea3b1181a132a245c0830a2788aea4cd1e9aefe..66fd2ec14f419d7273edddcb2324c2ddd4f996ab 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,22 @@ ![](mods/fabric/src/main/resources/beacon.png) +
+ +![https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/badges/dev/pipeline.svg) +![https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/badges/dev/coverage.svg) +![https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/releases](https://badgen.net/badge/version/0.1/blue) +![https://hub.docker.com/r/pas17/beacon](https://badgen.net/docker/pulls/pas17/beacon) + # Beacon -Fabric server performance and health monitoring made simple. Repository for the PDG project, HEIG-VD 2024-2025. +Minecraft server performance and health monitoring made simple. Repository for the PDG project, HEIG-VD 2024-2025. ## Project summary -Beacon is a suite of tools allowing Minecraft server owners or operators to monitor and interact with their server from a web interface, making it easier to troubleshoot performance issue causes and manage the server from another device. Hardware usage and limits are monitored to the extent of the JDK's limits and are combined with the server metrics and logs in order to create a pack of information that's useful to readily understand the server's current state. It includes code to build a Minecraft server-side mod for FabricMC, but it also allows developers to build it for other server types. The web server displays the server information, and allows the user to remotely interact with the server. Mod code has been written with JDK 21, while the web server uses Python 3.11 and Flask. Project was made as part of the PDG course in [HEIG-VD](https://heig-vd.ch/). +Beacon is a suite of tools allowing Minecraft server owners or operators to monitor and interact with their server from a web interface, making it easier to troubleshoot performance issue causes and manage the server from another device. Hardware usage and limits are monitored to the extent of the JDK's limits and are combined with the server metrics and logs in order to create a pack of information that's useful to readily understand the server's current state. It currently includes code to build a Minecraft server-side mod for FabricMC, but it also allows developers to build it for other server types. The web server displays the server information, and allows the user to remotely interact with the server. Mod code has been written with JDK 21, while the web server uses Python 3.11 and Flask. Project was made as part of the PDG course in [HEIG-VD](https://heig-vd.ch/). ## Used technologies @@ -53,12 +60,60 @@ The Gitlab pipeline contains following stages: - **Versioning**: calculates the version of the JAR files to be built - **Build**: used to build the JAR files for all supported Minecraft server types individually - **Test**: tests the common and server-specific codes. Test execution generates code coverage information -- **Imaging**: builds the Docker container image for the Beacon web server +- **Imaging**: builds and publishes the Docker container image for the Beacon web server - **Deploy**: deploys the landing page online, uploads built JAR files to the package registry. Tags commit and uploads source files with the calculated version into the repository To avoid having the CI/CD run in circles, the pipeline is only run if the commit is not tagged, as that is done automatically upon pushing to or merging into the main branch -## Docker Compose + +## Using our project + +### Mod + +Because our JAR files are published everytime a new release happens, you can head on to the [releases page](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/releases) and download the latest JAR for the Minecraft server type of your choice. + +#### Installing the mod on FabricMC + +First of all, [download and install FabricMC](https://fabricmc.net/use/installer/) on your computer. After the server files have been downloaded and extracted into the folder of your choice, create a folder named `mods` inside the server folder, and put the following files inside it: + +- The [Fabric API JAR file](https://www.curseforge.com/minecraft/mc-mods/fabric-api) (required to run mods in FabricMC servers) +- The mod's [released JAR file](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/releases) + +### Deploying the web server + +#### Manually + +If you wish to deploy the web server manually, you'll need Python installed (developed and tested with Python 3.10). After you've installed it, you can run the following commands to get the web server running: + +```sh +cd web/ +python -m venv .venv +pip install -r requirements.txt +flask run +``` + +#### Docker + +You can easily deploy our [ready-to-use Docker image](https://hub.docker.com/r/pas17/beacon) on a machine that has Docker installed. The web server runs on port 5000. The commands to deploy it are as follow: + +```sh +docker pull pas17/beacon:latest +docker run -d -p 5000:5000 pas17/beacon:latest +``` + +Depending on the OS you are in, you might need to specify the `host.docker.internal` used in the default configuration of the Dockerfile in order to access a server hosted in the same machine. + +```sh +docker run --add-host host.docker.internal:host-gateway -p 5000:5000 pas17/beacon:latest +``` + +Alternatively, if you host a minecraft server elsewhere, you can use the following : + +```sh +docker run -p 5000:5000 pas17/beacon:latest -e BEACON_HOST="" BEACON_PORT="" +``` + +**Note**: the port is already there despite not being able to change the port used by the mod. Can be useful if some sort of proxying is done on the minecraft server's machine. ## Contributing @@ -88,10 +143,14 @@ If you want to contribute, here's how to do it: 1. Create an issue describing what you're attempting to do in your commits, or pick one that already exists 2. From the issue's page, use the "Create merge request" button to create a branch from the most appropriate component branch and automatically create the merge request too. The name of your branch **must** start with the issue number. The merge request must use the "Feature merge" template 3. Commit as much as you want in your branch. Use this template for your commit message: `(#) Commit message` -4. After your development, make sure you're aligned with the component branch your you branched off of. +4. After your development, make sure you're aligned with the component branch you branched off of. 4. After your development, create a merge request from your branch to the corresponding component branch. A developer or maintainer will have a look at it, and either merge it, reject it (if this happens, don't worry, they'll give you a reason), or ask for changes 5. When a new version is ready to be released, merge requests will be open between each of the modified components and the development branch. A maintainer will review it, and follow the same procedure as listed in the step above. If everything is correct, the mod version is increased automatically when the merge request between the development and the root branches is merged. +### Contributing to the mod + +Check our [mod folder's README.md](./mods) for more information on this subject. + ## License This work is protected under the MIT License. Check the `LICENSE.txt` file for the full copyright. diff --git a/docs/README.md b/docs/README.md index 5b8263d3465e280b01150129b47cbb9f152a9b47..7f2db0418afe84a6a95aa3ebb9b3f8b58d3072b0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,5 +16,5 @@ In this folder, you'll find all the project's documentation, as well as any imag ## Opening the landing page's files -Because the landing page is fully written in HTML5, no specific tool is need to create it. Any simple text editor will do. The landing page's main file is `index.html` +Because the landing page is fully written in HTML5, no specific tool is needed to create it. Any simple text editor will do. The landing page's main file is `index.html`. diff --git a/docs/mockups/execute_cmd_seq.drawio b/docs/mockups/execute_cmd_seq.drawio new file mode 100644 index 0000000000000000000000000000000000000000..5f103d48b00ea86821bec9653cd28a5fd29e7a91 --- /dev/null +++ b/docs/mockups/execute_cmd_seq.drawio @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/execute_cmd_seq.svg b/docs/mockups/execute_cmd_seq.svg new file mode 100644 index 0000000000000000000000000000000000000000..81f68ffd7d2b8d46c25be91f7b4e66f7f21cea76 --- /dev/null +++ b/docs/mockups/execute_cmd_seq.svg @@ -0,0 +1,3 @@ + + +
:Web server
:Mod
Send command from server's dashboard
Supported
Not supported
Send error
Send CMD opcode
Server
Execute command
return
return
Silent return
\ No newline at end of file diff --git a/docs/mockups/handshake_capabilities_seq.drawio b/docs/mockups/handshake_capabilities_seq.drawio new file mode 100644 index 0000000000000000000000000000000000000000..8baf206dd93f2cce2207037d142685dcc03b704f --- /dev/null +++ b/docs/mockups/handshake_capabilities_seq.drawio @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/handshake_capabilities_seq.svg b/docs/mockups/handshake_capabilities_seq.svg new file mode 100644 index 0000000000000000000000000000000000000000..1db2e29d203d8a853e395286526f3caf29ef48ed --- /dev/null +++ b/docs/mockups/handshake_capabilities_seq.svg @@ -0,0 +1,3 @@ + + +
:Web server
:Mod
Send web server's CAP bitmap
Send mod's CAP bitmap
Compatible selections
Send ACK op.
Incompatible selections
Send NOK op.
Send mod's INF
\ No newline at end of file diff --git a/docs/mockups/handshake_crypto_seq.drawio b/docs/mockups/handshake_crypto_seq.drawio new file mode 100644 index 0000000000000000000000000000000000000000..563118aac4970652c2089a3916524b613abcf665 --- /dev/null +++ b/docs/mockups/handshake_crypto_seq.drawio @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/handshake_crypto_seq.svg b/docs/mockups/handshake_crypto_seq.svg new file mode 100644 index 0000000000000000000000000000000000000000..ecdc12102716e6fc2664ba0d8fc9775dda22a22a --- /dev/null +++ b/docs/mockups/handshake_crypto_seq.svg @@ -0,0 +1,3 @@ + + +
:Web server
:Mod
Open websocket
Accept connection
Send web server's CRY bitmap
Send mod's CRY bitmap
Send web server's SEL bitmap
Success
Send ACK op.
Server page opened
Compatible selections
Incompatible selections
Send web server's CRY bitmap
Send mod's CRY bitmap
Send web server's SEL bitmap
Compatible selections
Incompatible selections
Retry 1
No more retries
Success
Error
Send RTY op.
Send ACK op.
\ No newline at end of file diff --git a/docs/mockups/log_intercept_seq.drawio b/docs/mockups/log_intercept_seq.drawio new file mode 100644 index 0000000000000000000000000000000000000000..dfbaa0e75a424e83d0b3cdf75de2ac5180382b05 --- /dev/null +++ b/docs/mockups/log_intercept_seq.drawio @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/log_intercept_seq.svg b/docs/mockups/log_intercept_seq.svg new file mode 100644 index 0000000000000000000000000000000000000000..63f7da0e22554f3acf6a9396b1615cb4d8e71aef --- /dev/null +++ b/docs/mockups/log_intercept_seq.svg @@ -0,0 +1,3 @@ + + +
:Web server
:Mod
Web socket is active and handshake is over
Intercept log
Manage logs queue
Send LOG opcode with log
\ No newline at end of file diff --git a/docs/mockups/metrics.drawio b/docs/mockups/metrics.drawio new file mode 100644 index 0000000000000000000000000000000000000000..5b28bfa36bfc95a7972e8396d2e4ad921ec3532e --- /dev/null +++ b/docs/mockups/metrics.drawio @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/metrics.svg b/docs/mockups/metrics.svg new file mode 100644 index 0000000000000000000000000000000000000000..8dcbe7a4a1c82b27620c962744fad57633397e3e --- /dev/null +++ b/docs/mockups/metrics.svg @@ -0,0 +1,3 @@ + + +
Root
Mod metrics
Mod version
Server ID
Server name
Host metrics
OS
OS name
OS version
CPU arch
RAM
Heap - Free
Heap - Used
Heap - Max
Non-heap - Free
Non-heap - Used
Non-heap - Max
CPU
Usage (%)
JVM cores
I/O
Write speed
Read speed
JVM
Launch arguments
JRE version
Server metrics
Properties
Server type
Minecraft version
Online player count
Max player count
Uptime (secs)
Players [ ]
GUID
Username
Playtime (session)
Playtime (total)
Is OP?
Current world name
Position (X,Y,Z)
Health
Hunger
Hunger saturation
Worlds [ ]
Name
Dimensions [ ]
Current time
Current weather
Spawn point
Gamerules { }
. . .
/public
MOTD
Timestamp
Current world type
XP
Type
I/O delay (secs)
\ No newline at end of file diff --git a/docs/mockups/req_metrics_seq.drawio b/docs/mockups/req_metrics_seq.drawio new file mode 100644 index 0000000000000000000000000000000000000000..9d2da1ceaf2d3e6a83f9d7545818ce76b6f58bd7 --- /dev/null +++ b/docs/mockups/req_metrics_seq.drawio @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/req_metrics_seq.svg b/docs/mockups/req_metrics_seq.svg new file mode 100644 index 0000000000000000000000000000000000000000..7c7bc6615914ac454e93e41e225d9c4c63ae7166 --- /dev/null +++ b/docs/mockups/req_metrics_seq.svg @@ -0,0 +1,3 @@ + + +
:Web server
:Mod
Gather metrics
Web socket is active and handshake is over
Send MTR opcode
Send MTR opcode with JSON
\ No newline at end of file diff --git a/docs/mockups/websocket_mod_state.drawio b/docs/mockups/websocket_mod_state.drawio new file mode 100644 index 0000000000000000000000000000000000000000..98d47fc7b6fb799b5ac8796ed1b0a232568a244c --- /dev/null +++ b/docs/mockups/websocket_mod_state.drawio @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/websocket_mod_state.svg b/docs/mockups/websocket_mod_state.svg new file mode 100644 index 0000000000000000000000000000000000000000..ea00d818aaea56a8d6ceadcff9c014f78f497c5b --- /dev/null +++ b/docs/mockups/websocket_mod_state.svg @@ -0,0 +1,3 @@ + + +
Mod-side web socket communication
Resp. op. is not ACK
Exchange failed
Mod rejects handshake with op. NOK
[retried]
Mod rejects handshake with op. RTY
[not yet retried]
Mod accepts handshake with op. ACK
[key exchange needed]
Mod accepts handshake with op. ACK
[no key exchange needed]
Cryptographic algo. negotiation
Resp. op. is CRY
Other response
Wait for web server's crypto. selection
Resp. op. is SEL
Other response
Crypto. algo. selection with response bitmap
Send crypto. algo. selection
Accept web socket connection
Key exchange
TBD
Capability exchange
Send mod's capabilities
Other response
Wait for web server's capability message
Resp. op. is CAP
Log reception
Interruption
Log received
Wait for log
Send log through web socket
Resp. op. is ACK
Log received
Websocket request reception
Interruption
Tick
Wait for request
Handle request
Send status
Interruption
Close socket
Wait for web socket connection
Connection received
Send mod's information
Exchange success
\ No newline at end of file diff --git a/docs/mockups/websocket_web_state.drawio b/docs/mockups/websocket_web_state.drawio new file mode 100644 index 0000000000000000000000000000000000000000..ab36defcdd3fe9e94fec14b1ce5a2a00a763d927 --- /dev/null +++ b/docs/mockups/websocket_web_state.drawio @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/mockups/websocket_web_state.svg b/docs/mockups/websocket_web_state.svg new file mode 100644 index 0000000000000000000000000000000000000000..1af1d0232a93ef922af59bac345e2b0796287886 --- /dev/null +++ b/docs/mockups/websocket_web_state.svg @@ -0,0 +1,3 @@ + + +
Web server-side web socket communication
Web Server rejects handshake
Exchange failed
Other response
Resp. op. is RTY
Resp. op. is ACK
[key exchange needed]
Resp. op. is ACK
[no key exchange needed]
Cryptographic algo. negotiation
Resp. op. is CRY
Other response
Web server cryptographic negotiation
Resp. op. is SEL
Other response
Crypto. algo. selection with response bitmap
Compare selections
Open websocket to mod
Key exchange
TBD
Capability exchange
Compare capabilities
Other response
Web server capability message
Resp. op. is CAP
Log reception
Interruption
Log received
Wait for log
Register log
Web Server accepts handshake
with response op. ACK
Log received
Metric pooling
Interruption
Tick
Wait for tick
Resp. op.
is not MTR
Resp. op. is MTR
Request metrics
Acknowledge response
Interruption
User interaction
Interruption
Tick
Wait for interaction
Resp. op.
is ACK
Resp. op. is
not ACK
Send interaction to mod
Display error to user
Close socket
Other response
Wait for mod's information
Resp. op. is INF
Exchange success
\ No newline at end of file diff --git a/docs/mockups/metrics.png b/docs/report/metrics.png similarity index 100% rename from docs/mockups/metrics.png rename to docs/report/metrics.png diff --git a/docs/report/protocol.md b/docs/report/protocol.md new file mode 100644 index 0000000000000000000000000000000000000000..9fd9f65b7b0a7028c7df3e322bf0481054094dc6 --- /dev/null +++ b/docs/report/protocol.md @@ -0,0 +1,254 @@ +### General conventions + +- All numeric data is transmitted in big endianness +- The socket remains open for periodic updates, unless closure is called by any of the parties. +- Mod is the party that takes the decisions (commonly called "*master*") +- Web socket message format: `| Opcode (1B) | Data (nB) |` + +### Opcodes + +The following opcodes are supported as of this version. If an opcode is not listed, it is to be considered as an invalid opcode, and a response with opcode `0xFF NOK` should be returned. + +| Opcode | Name | Usage | +|:------:|---------|------------------------------------------------------| +| 0x00 | NOP | Unused (null byte) | +| 0x01 | ACK | Positive response to a request. Operation successful | +| 0x10 | CRY | Cryptographic algorithm negotiation bitmap | +| 0x11 | SEL | Cryptographic algorithm selection bitmap | +| 0x12 | KEY | (Iteration 3) Key exchange | +| 0x13 | CAP | Capabilities (features) negotiation bitmap | +| 0x20 | INF | Mod version information | +| 0x21 | MTR | Metrics request or response (depends on sender) | +| 0x22 | LOG | Log upload from mod to web server | +| 0x23 | CMD | Command sent from web server to mod | +| 0xFE | RTY | Retry request. Last request was invalid or corrupted | +| 0xFF | NOK | Negative response to a request. Operation failed | + +**NOTE:** `0x21 MTR Metrics` is to be seen as a metrics request opcode when sent by the web server, and a metrics response opcode when sent by the mod. + +#### `0x00 NOP No Operation` + +**Format:** `| Opcode (1B) |` + +Acts as a spacer, in case a keep-alive ping is needed. + +#### `0x01 ACK Acknowledge` + +**Format:** `| Opcode (1B) |` + +Lets the other party know the operation was successful, or accepted. + +#### `0x10 CRY Cryptography` + +**Format:** `| Opcode (1B) | Bitmap (16B) |` + +Used to let the other party know of this party's accepted cryptographic algorithms in the [Cryptographic handshake phase](#cryptographic-handshake-phase). + +#### `0x11 SEL Selection` + +**Format:** `| Opcode (1B) | Bitmap (16B) |` + +Used to let the other party know the result of the AND'd bitmap in the [Cryptographic handshake phase](#cryptographic-handshake-phase), for comparison and validation purposes. + +#### `0x12 KEY Key Exchange` + +**Format:** `| Opcode (1B) |` + +Yet to be implemented and described. (Iteration 3) + +#### `0x13 CAP Capability` + +**Format:** `| Opcode (1B) | Bitmap (16B) |` + +Used to let the other party know of this party's capabilities in the [Capability negotiation phase](#capability-negotiation-phase). + +#### `0x20 INF Information` + +**Format:** `| Opcode (1B) | Length (4B) | Data (nB) |` + +Includes the mod's information. Data is formatted as a JSON, and follows rules established in [Data Format](#data-format) + +#### `0x21 MTR Metrics` + +**Format (when sent by Web Werver):** `| Opcode (1B) |` +**Format (when sent by mod):** `| Opcode (1B) | Length (4B) | Data (nB) |` + +If sent by the Web Server, triggers the mod to export and send back the latest metrics it has. Data is formatted as a JSON, and follows rules established in [Data Format](#data-format) + +#### `0x22 LOG Log entries` + +**Format:** `| Opcode (1B) | Length (4B) | Data (nB) |` + +Includes all the queued log entries (50 max), or a log entry that has just been logged. Data is formatted as a simple string, and follows rules established in [Data Format](#data-format) + +#### `0x23 CMD Command` + +**Format:** `| Opcode (1B) | Length (4B) | Data (nB) |` + +Sends a command to be executed in the Minecraft server instance. Data is formatted as a simple string, and follows rules established in [Data Format](#data-format) + +#### `0xFE RTY Retry` + +**Format:** `| Opcode (1B) |` + +Used when the mod asks the Web Server to retry the [Cryptographic handshake phase](#cryptographic-handshake-phase) + +#### `0xFF NOK Not OK` + +**Format:** `| Opcode (1B) | Length (4B) | Reason (nB) |` + +Sent by the mod to inform the Web Server a request was unsuccessful or rejected. + +### Cryptographic handshake phase + +This phase follows this sequence : + +- Web Server sends bitmap with the `0x10 CRY Cryptography` opcode +- Mod sends bitmap with the `0x10 CRY Cryptography` opcode +- Web Server sends the AND'd bitmap with the `0x11 SEL Selection` opcode +- This phase finishes with: + - If the mod accepts the Web Server's AND'd bitmap (i.e. it is equivalent to the AND'd bitmap the mod has calculated), the mod sends an `0x01 ACK Acknowledge` opcode + - Else, if it's the second time the handshake is being done, the mod closes the socket + - Else, the mod sends a `0xFE RTY Retry` opcode + +Notes: + +- Only one retry is allowed before the socket's connection is closed by the mod +- Opening a new socket connection afterwards is not forbidden +- If the cryptography generation is *Legacy*, and all bits in the AND'd bitmap are 0, then the handshake fails (no available cryptography algorithm) + + +#### Cryptographic Algorithm bitmap (128 bits) + +- **Bits 0-1:** Cryptography generation + - `0b00`: Legacy (our first non-cryptographically safe version) + - `0b01`: First version of cryptographicly safe Beacon. May change along the life of this project (later version if crypto requires changes) + - `0b10` and `0b11`: RFU +- **Bits 2-33:** Key Exchange Protocols + - Bit 2: "None" (no encryption, legacy support, can (and should) be disabled) + - Bit 3: RSA-2048 + - Bit 4: RSA-4096 + - Bit 5: DH-2048 + - Bit 6: DH-4096 + - Bit 7: ECDH-P256 + - Bit 8: ECDH-P384 + - Bits 9-33: Reserved for future key exchange protocols +- **Bits 34-65:** Symmetric Encryption Algorithms + - Bit 34: AES-128-GCM + - Bit 35: AES-256-GCM + - Bit 36: ChaCha20-Poly1305 + - Bits 37-65: Reserved for future symmetric algorithms +- **Bits 66-127:** Reserved for future cryptographic features + +#### Algorithm Selection + +- The server performs a bitwise AND to determine mutually supported algorithms. + - If multiple algorithms are supported, the server selects the strongest mutually supported algorithm according to NIST-approved minimums, IETF protocol standards, and widely recognized industry best practices (e.g., Mozilla, OWASP). + - For Key Exchange: ECDH-P384 > ECDH-P256 > DH-4096 > DH-2048 > RSA-4096 > RSA-2048 > None + - For Symmetric Encryption: AES-256-GCM > ChaCha20-Poly1305 > AES-128-GCM +- Asymmetric key exchange (e.g., Diffie-Hellman, RSA) is used to securely negotiate session keys. These protocols allow both parties to agree on a symmetric key for fast, secure communication (similar to how TLS works). + - Asymmetric cryptography is used for the key exchange due to the nature of public/private keys where symmetric would need to manually pre-share a key if not for the key exchange protocols. + - Symmetric cryptography is used for the general communication due to their superiority in terms of speed. Keys will be generated through the key exchange protocol and will last until closure of the socket. +- Multiple algorithms may be supported for key exchange, but only one is chosen per session. +- Upon determining the used algorithm, if the cryptography version is not *Legacy*, all further communication will be encrypted to prevent attackers from fingerprinting mod versions based on supported features. + +### Capability negotiation phase + +After succeeding the cryptography handshake and, if needed, a key exchange, both parties need to inform each other of their capabilities (features it has or it can handle). The phase goes as follows: + +- Web Server sends a `0x13 CAP Capabilities` opcode +- Mod responds with a `0x13 CAP Capabilities` opcode +- This phase finishes with: + - Web Server responds with `0x01 ACK Acknowledge` if it agrees to finish the handshake + - Web Server closes the socket connection otherwise + +#### Features bitmap (128 bits) + +The client sends a 128-bit field listing supported metrics/features (e.g., CPU usage, RAM usage). Some fields won't be in the list and will always be sent, such as, but not only: + +- Mod information +- I/O delay +- Server's public information +- Free heap and non-heap RAM + +The bitmap will evolve with the added features upon development. As of the current version: + +- Bit 0: OS +- Bit 1: CPU arch +- Bit 2: JRE version +- Bit 3: JVM Cores +- Bit 4: CPU Usage +- Bit 5: RAM Heap max +- Bit 6: RAM Heap usage +- Bit 7: RAM Non-Heap max +- Bit 8: RAM Non-Heap usage +- Bit 9: Launch arguments +- Bit 10: Uptime +- Bit 11: Players list +- Bit 12: Worlds list +- Bit 13: Logs +- Bit 14: IO write speed delay +- Bit 15: IO read speed delay +- **Bits 16-127**: Reserved for future usage + +Notes: + +- Only features supported by both sides are enabled for the session (read handshake). + +### Secure Communication Phase + +#### Data Format + +- All string payloads are to be encoded in UTF-8 +- Each packet containing string payloads start with a 4-byte length field in network byte order (big-endian) + - The length field specifies the size of the following JSON payload in bytes + - Messages containing over 2^32 bytes of data are not allowed to be transmitted. In case this happens, data will be interpreted as incomplete +- JSON structure is used for flexible data representation while maintaining schema validation +- Multi-line, non-JSON data is to have `\n` as a line separator + +### Security Considerations + +- Legacy "None" encryption is discouraged and can be disabled for production. + +### Session Termination + +- Either side can request to close the socket. + - Upon request, both parties will close the socket no matter the circumstances. Closing should then be thoughtful to avoid constant closure and re-opening. +- Session keys and state are discarded upon closure. + +### State diagrams + +#### For web server + +![State diagram for the web server](../mockups/websocket_web_state.svg) + +#### For mod + +![State diagram for the mod](../mockups/websocket_mod_state.svg) + +### Sequence diagrams + +#### Cryptographic handshake + +![Sequence diagram for handshake for cryptographic algorithm selection](../mockups/handshake_crypto_seq.svg) + +#### Key exchange + +To be done in iteration 3 + +#### Capabilities handshake + +![Sequence diagram for handshake for supported capibilities](../mockups/handshake_capabilities_seq.svg) + +#### Command execution + +![Sequence diagram for command execution when trigerred by user](../mockups/execute_cmd_seq.svg) + +#### Intercepting and uploading logs + +![Sequence diagram for log entry being uploaded after being intercepted](../mockups/log_intercept_seq.svg) + +#### Metrics request and reception + +![Sequence diagram for web server requesting metrics from the mod, and mod responds](../mockups/req_metrics_seq.svg) + diff --git a/docs/report/quarto.qmd b/docs/report/quarto.qmd index 3bbb7f91ba448292b069a2d80eb2c22e1f2d0871..9b85bcb2c57155e26d3006a23da53c40a8066b4b 100644 --- a/docs/report/quarto.qmd +++ b/docs/report/quarto.qmd @@ -27,6 +27,8 @@ acronyms: longname: Network Address Translation - shortname: HTML longname: Hypertext Markup Language + - shortname: HTTP + longname: Hypertext Transfer Protocol - shortname: HTTPS longname: Hypertext Transfer Protocol Secure - shortname: SSH @@ -53,6 +55,12 @@ acronyms: longname: Transmission - shortname: Rx longname: Reception + - shortname: API + longname: Application Programming Interface + - shortname: URI + longname: Uniform Resource Identifier + - shortname: JSON + longname: JavaScript Object Notation --- ```{css} @@ -71,7 +79,7 @@ Version 0.1 # Abstract -Beacon is a suite of tools allowing Minecraft server owners or operators to monitor and interact with their server from a web interface, making it easier to troubleshoot performance issue causes and manage the server from another device. Hardware usage and limits are monitored to the extent of the {{< acr JDK >}}'s limits and are combined with the server metrics and logs in order to create a pack of information that's useful to readily understand the server's current state. It includes code to build a Minecraft server-side mod for FabricMC, but it also allows developers to build it for other server types. The web server displays the server information, and allows the user to remotely interact with the server. Mod code has been written with {{< acr JDK >}} 21, while the web server uses Python 3.11 and Flask. Project was made as part of the PDG course in [HEIG-VD](https://heig-vd.ch/). +Beacon is a suite of tools allowing Minecraft server owners or operators to monitor and interact with their server from a web interface, making it easier to troubleshoot performance issue and manage the server from another device. Hardware usage and limits are monitored to the extent of the {{< acr JDK >}}'s limits and are combined with the server metrics and logs in order to create a pack of information that's useful to readily understand the server's current state. It includes the code to build a Minecraft server-side mod for FabricMC, but it also allows developers to build it for other server types. The web server displays the server information, and allows the user to remotely interact with the server. Mod code has been written with {{< acr JDK >}} 21, while the web server uses Python 3.11 and Flask. Project was made as part of the PDG course in [HEIG-VD](https://heig-vd.ch/). # Project description @@ -139,7 +147,7 @@ These requirements apply to the third iteration only. Other iterations use featu - ([#3](https://gitlab.com/ps-heig1/beacon/-/work_items/3)) Source code is compatible with {{< acr JDK >}} version 21 or more recent - ([#3](https://gitlab.com/ps-heig1/beacon/-/work_items/3)) All server-side mod variants must use a shared library to ensure consistent data collection and parsing, no matter the server type - ([#3](https://gitlab.com/ps-heig1/beacon/-/work_items/3)) Changes in the common code is reflected in all server-side mods, whatever the server type -- ([#18](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/18)) The mod hosts an HTTP server that's capable of handling web sockets +- ([#18](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/18)) The mod hosts an {{< acr HTTP >}} server that's capable of handling web sockets - ([#31](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/31)) A snapshot of [all the metrics](#data-upload-and-visualization) are stored for the next metric requests - ([#31](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/31)) Data collection timestamp is recorded - ([#27](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/27)) Data collection is done every minute (auto-update) @@ -147,9 +155,9 @@ These requirements apply to the third iteration only. Other iterations use featu - ([#30](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/30)) When establishing the web-socket's connection, the mod takes into account the web server of its capabilities - ([#23](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/23)) Once the web-socket connection is established and authenticated, the 50 last log lines are sent to the web server - ([#22](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/22)) Secure communication through the socket is performed by encrypt data using two public/private key pairs: one to send data from the mod, one to send data from the web server -- ([#14](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/14)) An HTTP GET request on the `/heartbeat` endpoint results in an HTTP status 200 with no body -- ([#14](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/14)) An HTTP GET request on the `/public` endpoint returns the Minecraft server's information (name, {{< acr IP >}}, number of players online, maximum number of players) -- ([#27](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/27)) The web-socket is open upon receiving an HTTP GET request on the `/socket` endpoint +- ([#14](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/14)) An {{< acr HTTP >}} GET request on the `/heartbeat` endpoint results in an {{< acr HTTP >}} status 200 with no body +- ([#14](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/14)) An {{< acr HTTP >}} GET request on the `/public` endpoint returns the Minecraft server's information (name, {{< acr IP >}}, number of players online, maximum number of players) +- ([#27](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/27)) The web-socket is open upon receiving an {{< acr HTTP >}} GET request on the `/socket` endpoint - ([#27](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/27)) The web-socket is closed upon the other party disconnecting - ([#27](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/27)) The web-socket allows for data to be sent in both incoming and outgoing directions - ([#27](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/27)) If a web-socket is open, metrics are sent every minute @@ -158,7 +166,7 @@ These requirements apply to the third iteration only. Other iterations use featu - ([#32](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/32)) Any change to the mod's configuration via commands is saved into the mod's configuration file - ([#33](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/33)) Threads that the mod owns must use interruptible sleep - ([#32](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/32)) Server operators may query the mod's run state and information by using the [commands](#commands) -- ([#31](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/31)) Metrics unrelated to Minecraft-specific APIs must be collected via common library code +- ([#31](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/31)) Metrics unrelated to Minecraft-specific {{< acr API >}}s must be collected via common library code - ([#31](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/31)) Minecraft server-specific metrics must be provided by the mod via a callback interface registered with the common library - ([#32](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/32)) Commands for interacting with the mod may only be executed by server operators - ([#31](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/31)) Data collecting functions should check for impossible values (for example, negative numbers) and errors as return codes @@ -170,8 +178,8 @@ These requirements apply to the third iteration only. Other iterations use featu - ([#33](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/33)) Metrics collection must avoid causing noticeable lag spikes or freezes for players in the server. If collection takes more than 250ms, a warning message is written in the logs - ([#33](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/33)) No check needs to be performed to know whether data has been received by the web server -- ([#19](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/19)) Data collection and upload must work on any {{< acr OS >}}, and rely solely on publicly-available Java APIs -- ([#47](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/47)) Mod must work across minor updates of Minecraft server APIs with minimal changes +- ([#19](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/19)) Data collection and upload must work on any {{< acr OS >}}, and rely solely on publicly-available Java {{< acr API >}}s +- ([#47](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/47)) Mod must work across minor updates of Minecraft server {{< acr API >}}s with minimal changes - ([#33](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/33)) Errors in the mod must not crash the Minecraft server - ([#33](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/33)) Minecraft server crashes must not corrupt the mod's configuration file - ([#34](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/34)) Common source code coverage must be at least 80% @@ -200,9 +208,9 @@ These requirements apply to the third iteration only. Other iterations use featu - ([#16](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/16)) When the server list page is requested, a request is sent to each one of the server's heartbeat endpoint in order to detect whether the server is online or not - ([#16](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/16)) The heartbeat and public information request timeout is 2 seconds - ([#41](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/41)) The web server manages the Minecraft servers listed inside a configuration file containing a dictionary with an ID, {{< acr IP >}} / {{< acr FQDN >}}, port, and public key -- ([#40](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/40)) The list of servers is accessible at the homepage, with the URI `/` -- ([#40](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/40)) A server's dashboard is accessible with the URI `/dashboard/`, where `` is the ID of the server in the web server's configuration file -- ([#20](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/20)) The web-socket between the server dashboard and the web server is open upon receiving an HTTP GET request on the `/socket/` endpoint +- ([#40](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/40)) The list of servers is accessible at the homepage, with the {{< acr URI >}} `/` +- ([#40](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/40)) A server's dashboard is accessible with the {{< acr URI >}} `/dashboard/`, where `` is the ID of the server in the web server's configuration file +- ([#20](https://git-ext.iict-heig-vd.ch/PS-HEIG/beacon/-/issues/20)) The web-socket between the server dashboard and the web server is open upon receiving an {{< acr HTTP >}} GET request on the `/socket/` endpoint - (Too broad to assign an issue) The web server follows the sequence diagrams shown in [the Sequences section](#sequences) @@ -221,10 +229,10 @@ These requirements apply to the third iteration only. Other iterations use featu The first iteration allows us to have a very rudimentary proof-of-concept of the mod. It allows the developers to make sure that all the features intended to be implemented for the first release work were possible to be implemented and work correctly. The only metrics sent for this first iteration are heap memory information. - Mod - - HTTP endpoints - - `/heartbeat`: A simple endpoint that returns HTTP status code 200 + - {{< acr HTTP >}} endpoints + - `/heartbeat`: A simple endpoint that returns {{< acr HTTP >}} status code 200 - `/logs`: Shows the last 50 log lines as they were read from the log file - - `/metrics`: Shows a JSON dictionary containing three keys with `int` values: `heapFree`, `heapUsed`, `heapTotal` + - `/metrics`: Shows a {{< acr JSON >}} dictionary containing three keys with `int` values: `heapFree`, `heapUsed`, `heapTotal` - `/beacon`: Executes the `/beacon` command on the Minecraft server - Commands - `/beacon`: Sends "It's working" to the command source @@ -238,8 +246,8 @@ The first iteration allows us to have a very rudimentary proof-of-concept of the The second iteration keeps the same functionalities on both the mod and web server sides, but use a web-socket to communicate in both directions. The web page queries the mod's `/socket` endpoint to obtain a web-socket, and the mod is able to send logged messages as soon as they're logged via the same web-socket. The metrics sent in this iteration are all the [metrics](#metrics) section. - Mod - - HTTP endpoints - - `/heartbeat`: A simple endpoint that returns HTTP status code 200 + - {{< acr HTTP >}} endpoints + - `/heartbeat`: A simple endpoint that returns {{< acr HTTP >}} status code 200 - `/socket`: Opens a web-socket for communication between the mod and the web server instance. As soon as the socket is opened, metrics are sent. Accepted incoming messages: - 'cmd': executes the command the user typed - Commands @@ -248,7 +256,7 @@ The second iteration keeps the same functionalities on both the mod and web serv - Uses an hardcoded {{< acr IP >}} / {{< acr FQDN >}} and port to a Minecraft server - Queries the mod's `/socket` endpoint to obtain a web-socket, and creates a web-socket between itself and the mod. Accepted incoming messages: - 'logs': receives a new log line - - 'metrics': receives the server and OS / JVM metrics + - 'metrics': receives the server and {{< acr OS >}} / {{< acr JVM >}} metrics - When a user loads the homepage, displays the latest metrics and logs - Has a button that executes the `/beacon` command remotely - Has a field where the user can type a command to be executed on the Minecraft server. A button sends the command via the web-socket @@ -272,8 +280,8 @@ When the web-socket connection is opened and the authentication is successful, t More messages are to be added later on. - Mod: - - HTTP endpoints - - `/heartbeat`: A simple endpoint that returns HTTP status code 200 + - {{< acr HTTP >}} endpoints + - `/heartbeat`: A simple endpoint that returns {{< acr HTTP >}} status code 200 - `/public`: Returns public statistics (see requirement) - `/socket`: Opens a web-socket for communication between the mod and the web server instance @@ -295,7 +303,7 @@ More messages are to be added later on. As previously explained, the mod code is composed of two parts. -In order to preserve the common code's independence, the server-specific code calls common functions directly, while the common code calls server-specific code via callbacks. Following API is accessible from the server-side library to use the common library: +In order to preserve the common code's independence, the server-specific code calls common functions directly, while the common code calls server-specific code via callbacks. Following {{< acr API >}} is accessible from the server-side library to use the common library: ```java package me.peteras17.beacon; @@ -303,9 +311,16 @@ package me.peteras17.beacon; /** * Common library main class */ -@SuppressWarnings("unused") public final class BeaconCommon { + /** + * Compiled mod's version + */ + public static String VERSION = me.peteras17.beacon.ModVersion.VERSION; + + /** + * Default constructor + */ public BeaconCommon(); /** @@ -317,41 +332,42 @@ public final class BeaconCommon { public CommandManager getCmdManager(); /** - * Retrieves the root metric node - * @apiNote Call may be done before call to .beaconStart() - * @return Root node + * Returns the metrics manager instance + * @apiNote Registration of providers after call to .beaconStart() has no effect until call to .beaconStop() is made + * @return Metric manager instance */ - public MetricGroup getRootMetric(); - + public MetricManager getMetricManager(); /** - * Informs the common lib. that the server is up, and the mod has been loaded - * @param cfgPath Full path to the mod's configuration path + * Prepares Beacon's common library for a call to .beaconStart() * @param cmdRegisterCb Callback function receiving the command manager instance - * @throws RuntimeException Thrown if common code has already been started - * @return BeaconStatus.OK on success, or BeaconStatus.ERROR if an error occurred + * @return OK on success; + * TOO_HOT if this function has already been called */ - public int beaconStart(String cfgPath, Consumer cmdRegisterCb, Runnable beaconCmdCb) throws RuntimeException; + public BeaconStatus beaconPreHeat(Consumer cmdRegisterCb); /** - * Informs the common lib. that the server is about to stop - * @throws RuntimeException Thrown if common code has already been stopped + * Informs the common lib. that the server is up, and the mod has been loaded + * @param cfgPath Full path to the mod's configuration path + * @return OK if started; + * ALREADY_STARTED if .beaconStop() hasn't been called; + * TOO_COLD if call to .beaconPreHeat() is missing */ - public void beaconStop() throws RuntimeException; + public BeaconStatus beaconStart(String cfgPath, Function cmdExecutor); /** - * Executes a command entered by an operator - * @param command Command requested - * @param args List of command arguments - * @return BeaconStatus.OK on success, or any other value in case an error occurred (depending on the error) + * Informs the common lib. that the server is about to stop + * @apiNote Metrics need to be re-registered before calling .beaconStart() again + * @return OK if stopped; + * NOT_STARTED is a call to .beaconStart() has not been done yet */ - public BeaconStatus beaconExec(String command, Object[] args); + public BeaconStatus beaconStop(); } ``` ## Metrics -![Tree view of the metrics uploaded, in the JSON format, from the mod towards the web server via the web socket](../mockups/metrics.png) +![Tree view of the metrics uploaded, in the {{< acr JSON >}} format, from the mod towards the web server via the web socket](../mockups/metrics.svg) {{< include ./metrics.md >}} @@ -372,37 +388,9 @@ In order to allow users to manage the server remotely, the following game mechan - Send a global message - Send a message to a specific player -## Capabilities enumeration - -Both the web server and the mod exchange a bitmap that express their capabilities. In order to stay future-proof, the bitmap is 256 bits-wide, representing 256 different capabilities, in big-endian. `BigInteger` is used on the mod side, and Python 3's `int` is used on the web server side. The bitmap is yet to be decided - -## Sequences - -These sequences apply to the 3rd iteration of the product. Previous iterations may diverge from the intended sequences in order to make development easier. - -### Web-socket connection and authentication - -Diagram to be done - -### Capabilities exchange - -Diagram to be done - -### Transmission of logs from the mod - -Diagram to be done - -### Transmission of metrics from the mod - -Diagram to be done - -### Transmission of a message from the web server - -Diagram to be done - -### Web-socket closure and re-usage +## Protocol for communication between mod and web server -Diagram to be done +{{< include ./protocol.md >}} ## Azure resource group diff --git a/mods/README.md b/mods/README.md index d0ef46d76b346657a5acf411ef727b41b1ac719e..b18d03fa477da8fd12a4a0fe084922c8acdb00d4 100644 --- a/mods/README.md +++ b/mods/README.md @@ -43,7 +43,7 @@ dependencies { } ``` -Finally, if Gradle doesn't automatically detect these changes, close and re-open the project. The common library should be found in the left-side "Project" pane +Finally, if Gradle doesn't automatically detect these changes, close and re-open the project. The common library should be found in the left-side "Project" pane. ## Creating a new .java file @@ -78,3 +78,39 @@ Include the following header in every new file: */ ``` +## Contributing to the mod + +If you want to add a new feature, you need to: + +- Open an issue describing the metric you want to add, and why it should be added +- Create a branch from `mods` from your issue page, and start adding your metric + - Add the metric to the common library's `me.peteras17.beacon.cap.Capability` enumeration, under the correct category (check the comments) + - If the metric should be enabled by the default in the next version, add it to the `me.peteras17.beacon.cap.Capability.DEFAULT_FEATURES` array + - Make sure your metric's bit index does not overlap with already-existing metrics within the same category +- Fix any tests you might've broken +- Wait for a reviewer to stop by and approve, reject, or request changes! + +And then, depending on whether the feature involves adding a new metric or a command, check the correct section below. + +### Adding a new metric + +If you want to add a new metric that can be sent by the mod to the web server, you need to: + +- Follow the steps listed above, and then +- Make sure it can be retrieved in all the Minecraft server types we support +- On the server-side mod code, create a class the implements the interface `IMetricProvider`. You can take inspiration from already existing providers! 😊 +- Instantiate that metric provider class in the appropriate place +- Add the metric to the [metrics document](../docs/report/), and update the metrics tree file + +### Adding a new opcode + +If you want to add a new opcode that can be used in the communication between the mod and the web server, you need to: + +- Follow the steps listed above, and then +- Create a new opcode entry in the `me.peteras17.beacon.socket.Opcode` enumeration, under the correct category (check the comments) +- In the common library, create a new class that implements the interface `me.peteras17.beacon.socket.IOperation` + - If your opcode includes text in its payload, make your class extends `me.peteras17.beacon.socket.StringOp` +- If your opcode will be received by the mod via the web socket, do the following: + - Add your opcode to the `me.peteras17.beacon.SocketManager.OPCODE_TO_CLASS_MAP` map, so the mod's socket manager will detect it, and accept it + - Depending on what socket state should accept the opcode, you'll need to find the function that handles that state and edit it. For example, if the opcode is received only after the handshake phase, you'll need to add a case to the switch case in `.openState()` method inside the socket manager's class +- If your opcode will be sent by the mod via the web socket, find the appropriate state method in the `me.peteras17.beacon.SocketManager` class, and send the command from there diff --git a/mods/common/build.gradle.kts b/mods/common/build.gradle.kts index ca3ac639974d2784eb435b995c5768a7be5b3762..e304b24ca04b0a72d013e54b74df61951e46d3d4 100644 --- a/mods/common/build.gradle.kts +++ b/mods/common/build.gradle.kts @@ -21,10 +21,28 @@ dependencies { implementation("org.apache.logging.log4j:log4j-api:2.20.0") // Required for log interception implementation("org.apache.logging.log4j:log4j-core:2.20.0") // Required for log interception implementation("com.fasterxml.jackson.core:jackson-core:2.19.1") // Required to transform objects into JSON strings + implementation("org.glassfish.tyrus.bundles:tyrus-standalone-client:1.20") // Required to test WebSocket testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") } +// Automatically replace version in .java file when compiling +val generatedJavaDir = layout.buildDirectory.dir("generated/sources/java-templates") + +sourceSets["main"].java.srcDir(generatedJavaDir) + +tasks.register("processJavaTemplates") { + from("src/main/templates") + include("**/*.java.in") + into(generatedJavaDir) + expand("version" to project.version) // replace placeholders + rename { it.removeSuffix(".in") } // strip .in -> real .java +} + +tasks.named("compileJava") { + dependsOn("processJavaTemplates") +} + // Create test task tasks.test { useJUnitPlatform() @@ -45,6 +63,12 @@ tasks.jacocoTestReport { // Relocate libraries so Javalin can still work. Tutorial at https://javalin.io/tutorials/javalin-and-minecraft-servers tasks.shadowJar { + dependencies { + exclude(dependency("org.glassfish.tyrus.bundles:tyrus-standalone-client:1.20")) + exclude(dependency("org.junit:junit-bom:5.10.0")) + exclude(dependency("org.junit.jupiter:junit-jupiter")) + } + relocate("io.javalin:javalin:6.7.0", "shadow.io.javalin") relocate("org.slf4j:slf4j-simple:2.0.17", "shadow.org.slf4j") relocate("com.fasterxml.jackson.core:jackson-databind:2.13.2", "shadow.com.fasterxml.jackson.core") diff --git a/mods/common/src/main/java/me/peteras17/beacon/BeaconCommon.java b/mods/common/src/main/java/me/peteras17/beacon/BeaconCommon.java index c5ccc514c3005fbda18076cb547d46937f3648af..50a1c535c3831fcf084a842381fb629a0cdb094a 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/BeaconCommon.java +++ b/mods/common/src/main/java/me/peteras17/beacon/BeaconCommon.java @@ -1,17 +1,55 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 09/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.javalin.Javalin; import io.javalin.http.HttpStatus; +import me.peteras17.beacon.cap.*; import me.peteras17.beacon.cmd.ExecResult; -import me.peteras17.beacon.metrics.MemoryMetrics; import me.peteras17.beacon.logs.Interceptor; - -import java.util.function.Consumer; -import io.javalin.Javalin; +import me.peteras17.beacon.metrics.IMetric; import me.peteras17.beacon.metrics.MetricGroup; -import me.peteras17.beacon.metrics.MetricNode; import me.peteras17.beacon.metrics.MetricType; +import me.peteras17.beacon.metrics.providers.Host; +import me.peteras17.beacon.metrics.providers.Mod; +import me.peteras17.beacon.metrics.providers.Timestamp; +import me.peteras17.beacon.socket.ops.Cmd; import org.apache.logging.log4j.Level; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; +import java.util.function.Function; + /** * Common library main class */ @@ -19,34 +57,36 @@ import org.apache.logging.log4j.Level; public final class BeaconCommon { /** - * Is it the first time .beaconStart() is called? + * Compiled mod's version */ - private static boolean _firstStart = true; + public static String VERSION = me.peteras17.beacon.ModVersion.VERSION; /** - * Hardware metrics collection manager (manages the thread) + * Default address to bind Javalin to */ - private MetricManager _collectionMgr; + private static final String DEFAULT_HOST_BIND = "0.0.0.0"; /** - * Instance of the capability manager + * Default port to bind Javalin to */ - private final CapabilityManager _capMgr; + private static final int DEFAULT_PORT_BIND = 25566; /** - * Beacon mod commands manager + * Has a call to .beaconPreHeat() been done? */ - private final CommandManager _cmdMgr; + private boolean _heatedUp = false; /** - * Root node for all metrics + * Hardware metrics collection manager (manages the thread) */ - private final MetricGroup _metricsRoot; + private final MetricManager _metricMgr; /** - * Log interceptor instance + * Beacon mod commands manager */ - private Interceptor _logInterceptor; + private final CommandManager _cmdMgr; + private final SocketManager _socketMgr; + private final ICapability _features; /** * Javalin instance @@ -59,143 +99,186 @@ public final class BeaconCommon { private boolean _started = false; /** - * Deleted default constructor + * Callback to use to run received commands */ - public BeaconCommon() - { + Function cmdExecutor; + + /** + * Default constructor + */ + public BeaconCommon() { + // Setup capabilities + _features = new FeatCapability(); + _features.enable(Capability.DEFAULT_FEATURES); + + CryptoCapability cryptoAlgos = new CryptoCapability(); + cryptoAlgos.setCryptoGen(CryptoGen.CURRENT); + cryptoAlgos.enable(Capability.DEFAULT_CRYPTO_ALGOS); + + // Create managers _cmdMgr = new CommandManager(this); - _metricsRoot = new MetricGroup(MetricType.ROOT, Capability.BASE_METRICS); - _capMgr = new CapabilityManager(); - - // Enable base metrics - _capMgr.enable(Capability.BASE_METRICS); + _metricMgr = new MetricManager(new MetricGroup(MetricType.ROOT, Capability.ALWAYS_ACTIVE)); + _socketMgr = new SocketManager(this, cryptoAlgos, _features); + + // Create metric providers + _metricMgr.register(new Host()); + _metricMgr.register(new Mod()); + _metricMgr.register(new Timestamp()); } /** * Executes the command that retrieves the common library's status + * * @param context Command context. Unused * @return Execution result */ - ExecResult runStatusCommand(Object context) - { + ExecResult runStatusCommand(Object context) { + if(!_started) + { + return new ExecResult(BeaconStatus.NOT_STARTED, "Common library not started yet!"); + } return new ExecResult(BeaconStatus.OK, "It's working"); } /** * Retrieves the common library's command manager + * + * @return Command manager instance * @apiNote Call may be done before call to .beaconStart() * @apiNote Appending commands after call to .beaconStart() have no effect until server is restarted - * @return Command manager instance */ - public CommandManager getCmdManager() - { + public CommandManager getCmdManager() { return _cmdMgr; } /** - * Retrieves the root metric node - * @apiNote Call may be done before call to .beaconStart() - * @return Root node + * Returns the metrics manager instance + * + * @return Metric manager instance + * @apiNote Registration of providers after call to .beaconStart() has no effect until call to .beaconStop() is made */ - public MetricGroup getRootMetric() - { - return _metricsRoot; + public MetricManager getMetricManager() { + return _metricMgr; } /** - * Creates the common library metrics and adds them to the root node + * Prepares Beacon's common library for a call to .beaconStart() + * + * @param cmdRegisterCb Callback function receiving the command manager instance + * @return OK on success; + * TOO_HOT if this function has already been called */ - private void createCommonMetrics() - { - // Instantiate metric providers - MemoryMetrics memoryMetrics = new MemoryMetrics(); - - // Create metric objects - _metricsRoot.addMetric(new MetricNode(MetricType.HEAP_FREE, Capability.BASE_METRICS, memoryMetrics::getHeapFree)); - _metricsRoot.addMetric(new MetricNode(MetricType.HEAP_USED, Capability.BASE_METRICS, memoryMetrics::getHeapUsed)); - _metricsRoot.addMetric(new MetricNode(MetricType.HEAP_MAX, Capability.BASE_METRICS, memoryMetrics::getHeapMax)); + public BeaconStatus beaconPreHeat(Consumer cmdRegisterCb) { + if (_heatedUp) { + return BeaconStatus.TOO_HOT; + } + + cmdRegisterCb.accept(_cmdMgr); + _heatedUp = true; + return BeaconStatus.OK; } /** * Informs the common lib. that the server is up, and the mod has been loaded + * * @param cfgPath Full path to the mod's configuration path - * @param cmdRegisterCb Callback function receiving the command manager instance - * @throws RuntimeException Thrown if common code has already been started - * @return BeaconStatus.OK on success, or BeaconStatus.ERROR if an error occurred + * @return OK if started; + * ALREADY_STARTED if .beaconStop() hasn't been called; + * TOO_COLD if call to .beaconPreHeat() is missing */ - public int beaconStart(String cfgPath, Consumer cmdRegisterCb, Runnable beaconCmdCb) throws RuntimeException{ + public BeaconStatus beaconStart(String cfgPath, Function cmdExecutor) { - if(_started) { - throw new RuntimeException("Common code already started!"); + // Call to .beaconPreHeat() missing + if (!_heatedUp) { + return BeaconStatus.TOO_COLD; + } + + // Repeated call to .beaconStart() before .beaconStop() + if (_started) { + return BeaconStatus.ALREADY_STARTED; + } + + String hostBindStr = System.getProperty("BEACON_BIND", DEFAULT_HOST_BIND); + String portBindStr = System.getProperty("BEACON_PORT", Integer.toString(DEFAULT_PORT_BIND)); + + int portBind; + try { + portBind = Integer.parseInt(portBindStr); + }catch(NumberFormatException e) { + portBind = DEFAULT_PORT_BIND; } - // Create instances _started = true; - _collectionMgr = new MetricManager(_metricsRoot); - _logInterceptor = new Interceptor(50, Level.INFO); - - // Start collection manager - createCommonMetrics(); - + this.cmdExecutor = cmdExecutor; + + // Create instances + Interceptor logInterceptor = new Interceptor(50, Level.INFO, _socketMgr); + // Create HTTP endpoints _javalin = Javalin.create() - .get("/heartbeat", ctx -> ctx.status(HttpStatus.OK)) - .get("/logs", ctx -> { - ctx.result(String.join("\n", _logInterceptor.getLogs())); - ctx.status(HttpStatus.OK); - }) - .get("/metrics", ctx -> { - String jsonStr = _collectionMgr.getLastValues(_capMgr); - if(jsonStr == null) { - ctx.status(HttpStatus.INTERNAL_SERVER_ERROR); - } - else { - ctx.result(jsonStr); - ctx.status(HttpStatus.OK); - } - }) - .get("/beacon", ignoredCtx -> { - beaconCmdCb.run(); - }) - .start(25566); - - // Call command register function, but only the first time the mod is loaded - if(_firstStart) { - cmdRegisterCb.accept(_cmdMgr); - } + .get("/heartbeat", ctx -> ctx.status(HttpStatus.OK)) + .get("/public", ctx -> { + byte[] publicMetrics = getPublicInfo(); + byte[] payload = new byte[Integer.BYTES + publicMetrics.length]; + byte[] lengthBytes = ByteBuffer.allocate(Integer.BYTES) + .order(ByteOrder.BIG_ENDIAN) + .putInt(publicMetrics.length) + .array(); + + System.arraycopy(lengthBytes, 0, payload, 0, lengthBytes.length); + System.arraycopy(publicMetrics, 0, payload, lengthBytes.length, publicMetrics.length); - _firstStart = false; - return 0; + ctx.result(payload); + }) + .ws("/socket", wsConfig -> { + wsConfig.onBinaryMessage(_socketMgr::onSocketMessage); + wsConfig.onConnect(_socketMgr::onSocketConnect); + wsConfig.onClose(_socketMgr::onSocketClose); + }) + .start(hostBindStr, portBind); + _metricMgr.registerMetrics(); + return BeaconStatus.OK; } /** * Informs the common lib. that the server is about to stop - * @throws RuntimeException Thrown if common code has already been stopped + * + * @return OK if stopped; + * NOT_STARTED is a call to .beaconStart() has not been done yet + * @apiNote Metrics need to be re-registered before calling .beaconStart() again */ - public void beaconStop() throws RuntimeException { + public BeaconStatus beaconStop() { - if(!_started) { - throw new RuntimeException("Common code not started yet!"); + if (!_started) { + return BeaconStatus.NOT_STARTED; } - - // Stop Javalin + + _socketMgr.stop(); _javalin.stop(); - + _metricMgr.stopProviders(); _started = false; + return BeaconStatus.OK; } /** - * Executes a command entered by an operator - * @param command Command requested - * @param args List of command arguments - * @return BeaconStatus.OK on success, or any other value in case an error occurred (depending on the error) + * Retrieves the public information metrics, and serializes them + * + * @return Byte array containing the metrics' JSON */ - public BeaconStatus beaconExec(String command, Object[] args) { - - if(!_started) { - return BeaconStatus.NOT_STARTED; + private byte[] getPublicInfo() { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode rootNode = mapper.createObjectNode(); + + try { + IMetric publicMetric = _metricMgr.getMetric(MetricType.PROPERTIES); + if (null == publicMetric) { + throw new IllegalStateException(); + } + + publicMetric.serialize(rootNode, _features); + return mapper.writeValueAsString(rootNode).getBytes(StandardCharsets.UTF_8); + } catch (JsonProcessingException | IllegalStateException ignored) { + return new byte[]{'{', '}'}; } - - return BeaconStatus.OK; } } diff --git a/mods/common/src/main/java/me/peteras17/beacon/BeaconStatus.java b/mods/common/src/main/java/me/peteras17/beacon/BeaconStatus.java index b92f239746a37e0c47b86900331796bf88056b27..3f6c88c7c412ea29f3405f00b73ab3d5bbcc2784 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/BeaconStatus.java +++ b/mods/common/src/main/java/me/peteras17/beacon/BeaconStatus.java @@ -1,3 +1,30 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 09/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon; @@ -12,14 +39,19 @@ public enum BeaconStatus { OK, /** - * Informs the caller that the executed command is unknown + * Call to .beaconPreHeat() missing + */ + TOO_COLD, + + /** + * Call to .beaconPreHeat() already done */ - UNKNOWN_COMMAND, + TOO_HOT, /** - * Informs the caller the Beacon's common lib received invalid data on the parameters + * Repeated call to .beaconStart() before call to .beaconStop() has been done */ - INVALID_DATA, + ALREADY_STARTED, /** * Informs the caller the Beacon's common lib hasn't been started yet diff --git a/mods/common/src/main/java/me/peteras17/beacon/Capability.java b/mods/common/src/main/java/me/peteras17/beacon/Capability.java deleted file mode 100644 index e2df966da99be2604f0a0cb2d0461a2dbd7e8ef9..0000000000000000000000000000000000000000 --- a/mods/common/src/main/java/me/peteras17/beacon/Capability.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.peteras17.beacon; - -public enum Capability { - BASE_METRICS, - BASE_API, - EXTENDED_METRICS -} diff --git a/mods/common/src/main/java/me/peteras17/beacon/CapabilityManager.java b/mods/common/src/main/java/me/peteras17/beacon/CapabilityManager.java deleted file mode 100644 index 0fd7e9f47d6b746c8fc38d44763fe31445a9d2d4..0000000000000000000000000000000000000000 --- a/mods/common/src/main/java/me/peteras17/beacon/CapabilityManager.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.peteras17.beacon; - -import java.math.BigInteger; - -public class CapabilityManager { - - private BigInteger bitmap; - - public CapabilityManager() { - bitmap = BigInteger.ZERO; - } - - public void enable(Capability capability) { - bitmap = bitmap.setBit(capability.ordinal()); - } - - public void disable(Capability capability) { - bitmap = bitmap.clearBit(capability.ordinal()); - } - - public boolean supports(Capability capability) { - return bitmap.testBit(capability.ordinal()); - } -} diff --git a/mods/common/src/main/java/me/peteras17/beacon/CommandManager.java b/mods/common/src/main/java/me/peteras17/beacon/CommandManager.java index 4262f63ffe7051a7a7c3535f4a0a8e5f9530f5a2..0e38ad02143dfee603de929882d044fd96bd23ae 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/CommandManager.java +++ b/mods/common/src/main/java/me/peteras17/beacon/CommandManager.java @@ -1,3 +1,30 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 18/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon; import me.peteras17.beacon.cmd.Command; @@ -21,6 +48,7 @@ public class CommandManager { /** * Creates a new command manager instance + * * @param commonInstance Common library instance */ CommandManager(BeaconCommon commonInstance) { @@ -29,28 +57,29 @@ public class CommandManager { /** * Gets a command handler, based on a provided parent command - * @param fullCommand Full executed command string that serves as arguments or subcommands + * + * @param fullCommand Full executed command string that serves as arguments or subcommands * @param parentCommand Parent command to use * @return Command if handler found, null if no handler was found */ private Command getHandler(String fullCommand, Command parentCommand) { String[] parts = fullCommand.split(" "); - + // Use root command if needed - if(parentCommand == null) { + if (parentCommand == null) { parentCommand = rootCommand; } - + // Command name not in full command (weird?), or executed command mustn't be executed by Beacon - if(parts.length == 0 || !parentCommand.getName().equals(parts[0])) { + if (parts.length == 0 || !parentCommand.getName().equals(parts[0])) { return null; } - + // Command takes arguments, and we have them, or no subcommand requested - if((parts.length > 1 && parentCommand.takesArgs()) || (parts.length == 1 && !parentCommand.takesArgs())) { + if ((parts.length > 1 && parentCommand.takesArgs()) || (parts.length == 1 && !parentCommand.takesArgs())) { return parentCommand; } - + // Match subcommands recursively return this.getHandler(String.join(" ", Arrays.copyOfRange(parts, 1, parts.length)), parentCommand); } @@ -58,6 +87,7 @@ public class CommandManager { /** * Gets a command handler for the entered command + * * @param fullCommand Full executed command string that serves as arguments or subcommands * @return Command if handler found, null if no handler was found */ @@ -68,6 +98,7 @@ public class CommandManager { /** * Returns the root command's instance + * * @return Instance */ @SuppressWarnings("unused") // Used in server-specific code diff --git a/mods/common/src/main/java/me/peteras17/beacon/MetricManager.java b/mods/common/src/main/java/me/peteras17/beacon/MetricManager.java index ae43fdeda659b964229796e24809d6961c8c55d6..bc75dd49e846d5f3c6f2ef843565e493f01fcc01 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/MetricManager.java +++ b/mods/common/src/main/java/me/peteras17/beacon/MetricManager.java @@ -1,43 +1,153 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 09/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import me.peteras17.beacon.cap.ICapability; +import me.peteras17.beacon.metrics.IMetric; +import me.peteras17.beacon.metrics.IMetricProvider; import me.peteras17.beacon.metrics.MetricGroup; import me.peteras17.beacon.metrics.MetricType; -import java.util.*; -import java.util.logging.Logger; - -class MetricManager { +import java.util.LinkedList; +import java.util.List; +public class MetricManager { - + /** + * Root metric group + */ private final MetricGroup _root; + /** + * List of all metric providers + */ + private final List _providers; + + /** + * Used to know whether a call to .register() has already been done + */ + private boolean _registered; + /** * Instantiates a new hardware metrics collection thread * Does not automatically start the thread */ - MetricManager(MetricGroup root) - { + MetricManager(MetricGroup root) { _root = root; + _providers = new LinkedList<>(); + _registered = false; + } + + + /** + * Register all metrics provided by the metric providers that have been + * registered before the call to this function + * + * @apiNote Thread-safe code + */ + void registerMetrics() { + synchronized (_providers) { + + // Only allow call once + if (_registered) { + throw new IllegalStateException("Providers have already been registered!"); + } + + for (IMetricProvider provider : _providers) { + provider.register(_root); + } + + _registered = true; + } + } + + /** + * Requests all providers to stop + */ + void stopProviders() { + synchronized (_providers) { + for (IMetricProvider provider : _providers) { + provider.stop(); + } + } + + _providers.clear(); + } + + + /** + * Registers a new metric provider + * + * @param provider Provider instance + * @apiNote Thread-safe code + */ + public void register(IMetricProvider provider) { + synchronized (_providers) { + _providers.add(provider); + } + } + + + /** + * Returns the metric for the provided metric type + * + * @param type Type to find + * @return Instance, if found + * @throws IllegalArgumentException Thrown if instance is not found + */ + public IMetric getMetric(MetricType type) throws IllegalArgumentException { + synchronized (_providers) { + IMetric metric = _root.findMetric(type); + if (metric != null) { + return metric; + } + } + + throw new IllegalArgumentException("No metric object found for provided type"); } - + /** * Get last metrics values, in a JSON format + * * @return Values */ - String getLastValues(CapabilityManager capabilityManager) - { + public String getLastValues(ICapability capabilityManager) { ObjectMapper mapper = new ObjectMapper(); - + try { ObjectNode rootNode = mapper.createObjectNode(); _root.serialize(rootNode, capabilityManager); return mapper.writeValueAsString(rootNode); - }catch(JsonProcessingException | IllegalStateException ignored) { + } catch (JsonProcessingException | IllegalStateException ignored) { return null; } } diff --git a/mods/common/src/main/java/me/peteras17/beacon/SocketManager.java b/mods/common/src/main/java/me/peteras17/beacon/SocketManager.java new file mode 100644 index 0000000000000000000000000000000000000000..7499f48f4f96fa218e7b0eb597b2c67f73e50813 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/SocketManager.java @@ -0,0 +1,671 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon; + +import io.javalin.websocket.WsBinaryMessageContext; +import io.javalin.websocket.WsCloseContext; +import io.javalin.websocket.WsConnectContext; +import io.javalin.websocket.WsContext; +import me.peteras17.beacon.cap.*; +import me.peteras17.beacon.cmd.ExecResult; +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; +import me.peteras17.beacon.socket.SocketState; +import me.peteras17.beacon.socket.ops.*; +import org.eclipse.jetty.websocket.core.CloseStatus; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.function.Function; + +/** + * Class to manage a WebSocket + */ +public class SocketManager { + + public static final Logger LOGGER = LoggerFactory.getLogger(SocketManager.class.getName()); + + /** + * Number of milliseconds between each ping to keep the connection alive + */ + private static final int PING_INTERVAL_MS = 2000; + + /** + * Has the crypto capability negotiation (CRY and SEL) been retried? + */ + private boolean _retriedCryptoNeg; + + /** + * Current state of the socket + */ + private SocketState _state; + + /** + * Socket instance + */ + private WsContext _socket; + + /** + * Mod's cryptographic capabilities + */ + private final CryptoCapability _modCryptoCap; + + /** + * Mod's feature capabilities + */ + private final ICapability _modFeatCap; + + /** + * Socket's negotiated cryptographic capabilities + */ + private CryptoCapability _socketCryptoCap; + + /** + * Socket's negotiated feature capabilities + */ + private ICapability _socketFeatCap; + + /** + * Beacon's common library instance + */ + private final BeaconCommon _commonLib; + + /** + * List of sessions that the socket manager intentionally closed, so they don't trigger .onSocketClose() + */ + private final List _closedSessions; + + /** + * Semaphore used to block critical sections + */ + private final Semaphore _critSectionSem; + + /** + * Thread to keep a session alive + * @implNote Javalin supports an automatic pinging system, but it somehow prevents the Minecraft servers from stopping + */ + private Thread _sessionKeepAliveThread; + + /** + * Mapping between opcode and operation class + * + * @implNote Only contains opcodes that may be received through the socket + */ + private static final Map> OPCODE_TO_CLASS_MAP = Map.of( + Opcode.LOG, Nop.class, + Opcode.CRY, Cry.class, + Opcode.SEL, Sel.class, + Opcode.NOK, Nok.class, + Opcode.ACK, Ack.class, + Opcode.CAP, Cap.class, + Opcode.KEY, Key.class, + Opcode.NOP, Nop.class, + Opcode.CMD, Cmd.class, + Opcode.MTR, WebMtr.class + ); + + /** + * Mapping between a socket state and its state machine handler + */ + private final Map> STATE_TO_CALLBACK_MAP = Map.of( + SocketState.WAIT_WEB_CRY, this::waitWebCryState, + SocketState.WAIT_WEB_SEL, this::waitWebSelState, + SocketState.RETRY_WAIT_WEB_CRY, this::waitWebCryState, + SocketState.RETRY_WAIT_WEB_SEL, this::waitWebSelState, + SocketState.EXCHANGE_KEYS, this::exchangeKeysState, + SocketState.WAIT_WEB_CAP, this::waitWebCapState, + SocketState.WAIT_CAP_ACK, this::waitCapAckState, + SocketState.OPEN, this::openState + ); + + /** + * Creates a new socket manager instance + * + * @param commonLib Beacon's common library instance + * @param modCryptoCap Mod's cryptographic algorithm capabilities + * @param modFeatCap Mod's feature capabilities + */ + SocketManager(BeaconCommon commonLib, CryptoCapability modCryptoCap, ICapability modFeatCap) { + _commonLib = commonLib; + _modCryptoCap = modCryptoCap; + _modFeatCap = modFeatCap; + _closedSessions = new LinkedList<>(); + _retriedCryptoNeg = false; + _socket = null; + _state = SocketState.CLOSED; + _critSectionSem = new Semaphore(1); + } + + + /** + * Sends a payload through the socket, provided a socket connection is open + * + * @param op Operation to send + */ + public boolean sendOp(@NotNull IOperation op) { + + boolean sent = false; + + // Web socket thread currently in a critical section + // Ignore log sending if it's disabled + if(_critSectionSem.tryAcquire() && !isFree()) { + if (op.getOpcode() == Opcode.LOG) { + // Only send if the handshake is over, and logs can be sent + if (_state == SocketState.OPEN) { + if (_socketFeatCap.supports(Capability.FEAT_LOGS)) { + _socket.send(op.serialize()); + } + + // Green light, even if it wasn't really sent just because logs are disabled + sent = true; + } + } + else { + _socket.send(op.serialize()); + sent = true; + } + + } + _critSectionSem.release(); + + return sent; + } + + + public void stop() { + // Critical section + _critSectionSem.acquireUninterruptibly(); + { + // Force close connection + if (!isFree()) { + closeSession(); + } + } + _critSectionSem.release(); + } + + /** + * Returns whether the socket is ready to receive a connection + * + * @return True if ready to receive a connection, false if already in use + */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private boolean isFree() { + return _state == SocketState.CLOSED; + } + + /** + * Handler used to handle messages being received on the socket + * + * @param ctx Socket context + */ + void onSocketMessage(WsBinaryMessageContext ctx) { + Opcode opcode; + byte[] payload = ctx.data(); + IOperation operation; + + try { + // No payload + if (payload.length == 0) { + throw new IllegalArgumentException("Payload is empty"); + } + + // Unable to find a known opcode + opcode = Opcode.fromOp(payload[0]); + if (!OPCODE_TO_CLASS_MAP.containsKey(opcode)) { + throw new IllegalArgumentException("Opcode has no handler!"); + } + + // Instantiate and build operation from payload + Class clazz = OPCODE_TO_CLASS_MAP.get(opcode); + operation = clazz.getDeclaredConstructor().newInstance(); + operation.buildFrom(payload); + + } catch (IllegalArgumentException e) { + LOGGER.warn("Socket message dropped: {}", e.getMessage()); + sendOp(new Nok(e.getMessage())); + _socket.closeSession(CloseStatus.PROTOCOL, "Protocol violated"); + return; + } catch (InvocationTargetException | InstantiationException | IllegalAccessException | + NoSuchMethodException e) { + LOGGER.warn("Failed to create operation object from payload: {}", e.getMessage()); + sendOp(new Nok(e.getMessage())); + _socket.closeSession(CloseStatus.BAD_DATA, "Invalid data"); + return; + } + + // Critical section + IOperation outOp = advanceState(operation); + if (outOp != null) { + sendOp(outOp); + LOGGER.debug("Responded to opcode {} with opcode {}", operation.getOpcode(), outOp.getOpcode()); + } + } + + /** + * Handler used to handle socket connection + * + * @param ctx Socket context + */ + void onSocketConnect(WsConnectContext ctx) { + LOGGER.info("WebSocket connection from {}", ctx.session.getRemoteAddress()); + + // Critical section + _critSectionSem.acquireUninterruptibly(); + { + // Ignore if socket's already in use + if (!isFree()) { + _closedSessions.add(ctx.sessionId()); + + // Closing the session will require critical section again + _critSectionSem.release(); + + ctx.closeSession(CloseStatus.TRY_AGAIN_LATER, "Socket is already in use"); + LOGGER.warn("Another client, {}, tried to connect to socket when it's already in use", ctx.session.getRemoteAddress()); + return; + } + else { + _state = SocketState.WAIT_WEB_CRY; + _socket = ctx; + _socketCryptoCap = (CryptoCapability) _modCryptoCap.copy(); + _socketFeatCap = _modFeatCap.copy(); + _retriedCryptoNeg = false; + + // Create a thread to keep the connection open + // Read field's comment for more information + _sessionKeepAliveThread = new Thread(() -> { + while(!Thread.interrupted()) { + _socket.sendPing(); + try { + //noinspection BusyWait + Thread.sleep(PING_INTERVAL_MS); + } catch (InterruptedException ignoredE) { + LOGGER.info("Connection keep-alive exiting"); + break; + } + } + }); + _sessionKeepAliveThread.setName("Beacon WS Keep-Alive"); + _sessionKeepAliveThread.start(); + } + + LOGGER.info("WebSocket connected to {}", ctx.session.getRemoteAddress()); + + // Make this thread more important, to not make peer wait too long + Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1); + } + _critSectionSem.release(); + } + + /** + * Handler used to handle socket closing + * + * @param ctx Socket context + */ + void onSocketClose(WsCloseContext ctx) { + + // Critical section + _critSectionSem.acquireUninterruptibly(); + { + // Reset socket state only if in use, and if closing was not provoked by Beacon + if (!isFree()) { + if (_closedSessions.contains(ctx.sessionId())) { + _closedSessions.remove(ctx.sessionId()); + } else { + destroySession(); + LOGGER.info("Socket closed with reason: {}", ctx.reason()); + + // Revert priority + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + } + } + } + _critSectionSem.release(); + } + + + /** + * Post-session closing steps + */ + private void destroySession() + { + _sessionKeepAliveThread.interrupt(); + try { + _sessionKeepAliveThread.join(); + } catch (InterruptedException e) { + LOGGER.error("Failed to stop WS keep-alive thread"); + } + _socketCryptoCap = null; + _socketFeatCap = null; + _state = SocketState.CLOSED; + } + + + /** + * Makes sure the socket is destroyed + * + * @param status Status of closure + * @param reason Reason of closure + * + * @implNote Call must be done from a critical section + */ + private void closeSession(int status, String reason) { + destroySession(); + _socket.closeSession(status, reason); + _socket = null; + } + + /** + * Makes sure the socket is destroyed + * + * @implNote Call must be done from a critical section + */ + private void closeSession() { + closeSession(CloseStatus.NORMAL, "Socket closed"); + } + + /** + * Advances the state machine + * + * @param input Input operation + * @return New operation instance, or null if no need to send data + * @implNote Call must be done from a critical section + */ + private IOperation advanceState(IOperation input) { + IOperation op = null; + + // I mean, it's in the name of the operation... + if (input instanceof Nop) { + return null; + } + + // Check whether the current socket state can be handled. If it's not the case, we're... kind of in a pickle + _critSectionSem.acquireUninterruptibly(); + { + if (!STATE_TO_CALLBACK_MAP.containsKey(_state)) { + LOGGER.error("Unknown state to handle: {}", this._state); + if (_socket != null) { + // Closing the session will require critical section again + _critSectionSem.release(); + closeSession(CloseStatus.SERVER_ERROR, "Unknown state"); + return null; + } + } else { + try { + op = STATE_TO_CALLBACK_MAP.get(_state).apply(input); + } catch (RuntimeException e) { + LOGGER.error("Failed to advance state machine: {}", e.getMessage()); + if (_socket != null) { + // Closing the session will require critical section again + _critSectionSem.release(); + closeSession(CloseStatus.SERVER_ERROR, "State machine internal error"); + return null; + } + } + } + } + _critSectionSem.release(); + + return op; + } + + /** + * Handles the SocketState.WAIT_WEB_CRY state + * + * @param input Received operation object + * @return Next operation object + * @throws RuntimeException Thrown if input object is of wrong type + */ + private IOperation waitWebCryState(IOperation input) throws RuntimeException { + // Cast into right type + if (!(input instanceof Cry cry)) { + throw new RuntimeException("Wrong input operation type!"); + } + + // Intersect capabilities, and return mod's crypto. capabilities + _socketCryptoCap.intersect(cry.capability); + Cry retOp = new Cry(_modCryptoCap); + + // Advance state + _state = SocketState.WAIT_WEB_SEL; + + return retOp; + } + + /** + * Handles the SocketState.WAIT_WEB_SEL state + * + * @param input Received operation object + * @return Next operation object + * @throws RuntimeException Thrown if input object is of wrong type, or handshake failed + */ + private IOperation waitWebSelState(IOperation input) throws RuntimeException { + // Cast into right type + if (!(input instanceof Sel sel)) { + throw new RuntimeException("Wrong input operation type!"); + } + + // Make sure calculated intersection and received intersection are the same, and not all empty. If not, retry (if possible) + IOperation retOp; + if (!sel.capability.equals(_socketCryptoCap) + || (sel.capability.equals(new FeatCapability()) && _socketCryptoCap.getCryptoGen() != CryptoGen.LEGACY)) { + if (_retriedCryptoNeg) { + throw new RuntimeException("Cryptographic handshake failed two times in a row!"); + } + + // Give it a second change + _retriedCryptoNeg = true; + retOp = new Rty(); + LOGGER.warn("Cryptographic handshake failed. Retrying"); + _state = SocketState.RETRY_WAIT_WEB_CRY; + } else { + Capability exchangeCrypto = getSocketExchCrypto(); + Capability symmetricCrypto = getSocketSymmCrypto(); + + LOGGER.info("Cryptographic handshake concluded with key exchange {} and symmetric encryption {}", exchangeCrypto, symmetricCrypto); + retOp = new Ack(); + + if (Capability.NO_CRYPTO != exchangeCrypto) { + _state = SocketState.EXCHANGE_KEYS; + } else { + _state = SocketState.WAIT_WEB_CAP; + } + } + + return retOp; + } + + /** + * Handles the SocketState.EXCHANGE_KEYS state + * + * @param ignoredInput Received operation object + * @return Next operation object + * @throws RuntimeException Thrown if input object is of wrong type, or exchange failed + */ + private IOperation exchangeKeysState(IOperation ignoredInput) throws RuntimeException { + throw new RuntimeException("Not implemented yet!"); + } + + /** + * Handles the SocketState.WAIT_WEB_CAP state + * + * @param input Received operation object + * @return Next operation object + * @throws RuntimeException Thrown if input object is of wrong type, or exchange failed + */ + private IOperation waitWebCapState(IOperation input) throws RuntimeException { + // Cast into right type + if (!(input instanceof Cap cap)) { + throw new RuntimeException("Wrong input operation type!"); + } + + // Intersect capabilities, and send mod's capabilities + _socketFeatCap.intersect(cap.capability); + Cap modCap = new Cap(_modFeatCap); + _state = SocketState.WAIT_CAP_ACK; + return modCap; + } + + /** + * Handles the SocketState.WAIT_CAP_ACK state + * + * @param input Received operation object + * @return Next operation object + * @throws RuntimeException Thrown if input object is of wrong type, or exchange failed + */ + private IOperation waitCapAckState(IOperation input) throws RuntimeException { + // Cast into right type + if (!(input instanceof Ack)) { + throw new RuntimeException("Response was not ACK"); + } + + // Send mod's information, and set socket's state as open + Inf modInfo = new Inf(_commonLib, _socketFeatCap); + LOGGER.info("Handshake complete! WebSocket open"); + + // Send response before setting state to open to avoid having logs being sent before + _socket.send(modInfo.serialize()); + _state = SocketState.OPEN; + + return null; + } + + /** + * Handles the SocketState.OPEN state + * + * @param input Received operation object + * @return Next operation object + * @throws RuntimeException Thrown if input object is of wrong type, or exchange failed + */ + private IOperation openState(IOperation input) throws RuntimeException { + switch (input.getOpcode()) { + case MTR -> { + return new ModMtr(_commonLib, _socketFeatCap); + } + case CMD -> { + LOGGER.info("Received order to execute command /{}", ((Cmd)input).command); + ExecResult result = _commonLib.cmdExecutor.apply((Cmd)input); + if(result.status() != BeaconStatus.OK) + { + return new Nok(); + } + + return new Ack(); + } + default -> { + return new Nok("Invalid opcode!"); + } + } + } + + /** + * Returns the negotiated key exchange algorithm to be used for socket + * + * @return Algorithm capability + * @throws RuntimeException Thrown if no algorithm is available + */ + private Capability getSocketExchCrypto() throws RuntimeException { + Capability preferred = null; + + // No exchange for legacy crypto + if (_socketCryptoCap.getCryptoGen() == CryptoGen.LEGACY) { + return Capability.NO_CRYPTO; + } + + // Stop at first found + for (Capability cap : Capability.CRYPTO_EXCH_PREFERENCES) { + if (_socketCryptoCap.supports(cap)) { + preferred = cap; + break; + } + } + + if (null == preferred) { + throw new RuntimeException("No in-common exchange algorithm"); + } + + return preferred; + } + + /** + * Returns the negotiated symmetric cryptographic algorithm to be used for socket + * + * @return Algorithm capability + * @throws RuntimeException Thrown if no algorithm is available + */ + private Capability getSocketSymmCrypto() throws RuntimeException { + Capability preferred = null; + + // No exchange for legacy crypto + if (_socketCryptoCap.getCryptoGen() == CryptoGen.LEGACY) { + return Capability.NO_CRYPTO; + } + + // Stop at first found + for (Capability cap : Capability.CRYPTO_SYMM_PREFERENCES) { + if (_socketCryptoCap.supports(cap)) { + preferred = cap; + break; + } + } + + if (null == preferred) { + throw new RuntimeException("No in-common symmetric algorithm"); + } + + return preferred; + } + + /** + * Gets this socket's state + * @return Web socket state + */ + SocketState getState() + { + return _state; + } + + /** + * Gets the remote peer's address if socket is open, or null if closed + * @return Remote peer's address + */ + @SuppressWarnings("unused") + String getRemoteAddr() + { + if(_socket != null) { + return _socket.session.getRemoteAddress().toString(); + } + return null; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/cap/Capability.java b/mods/common/src/main/java/me/peteras17/beacon/cap/Capability.java new file mode 100644 index 0000000000000000000000000000000000000000..0dd6c7c10c83ea710634d26460e69e2cc5c2e6e3 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/cap/Capability.java @@ -0,0 +1,261 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + +public enum Capability { + + /* ************ / + * SPECIAL CASE * + / **************/ + + /** + * Metric is always active + */ + ALWAYS_ACTIVE(-1), + + /* ************ / + * CRYPTOGRAPHY * + / **************/ + + /** + * No key exchange + */ + NO_CRYPTO(2), + + /** + * RSA-2048 key exchange supported + */ + CRYPTO_EXCH_RSA2048(3), + + /** + * RSA-4096 key exchange supported + */ + CRYPTO_EXCH_RSA4096(4), + + /** + * Diffie-Hellman 2048b key exchange supported + */ + CRYPTO_EXCH_DH2048(5), + + /** + * Diffie-Hellman 4096b key exchange supported + */ + CRYPTO_EXCH_DH4096(6), + + /** + * Elliptic Curve + Diffie-Hellman, with NIST P256 key exchange supported + */ + CRYPTO_EXCH_ECDHP256(7), + + /** + * Elliptic Curve + Diffie-Hellman, with NIST P384 key exchange supported + */ + CRYPTO_EXCH_ECDHP384(8), + + /** + * Encryption using AES 128b supported + */ + CRYPTO_SYMM_AES128GCM(34), + + /** + * Encryption using AES 256b supported + */ + CRYPTO_SYMM_AES256GCM(35), + + /** + * Encryption using ChaCha20-Poly1305 supported + */ + CRYPTO_SYMM_CHACHA20POLY1305(36), + + + /* ************ / + * FEATURES * + / **************/ + + /** + * OS metrics supported + */ + FEAT_OS(0), + + /** + * CPU architecture metrics supported + */ + FEAT_CPU_ARCH(1), + + /** + * JRE version metrics supported + */ + FEAT_JRE_VERSION(2), + + /** + * JVM cores metrics supported + */ + FEAT_JVM_CORES(3), + + /** + * CPU usage metrics supported + */ + FEAT_CPU_USAGE(4), + + /** + * Max amount of heap RAM metrics supported + */ + FEAT_RAM_HEAP_MAX(5), + + /** + * Used amount of heap RAM metrics supported + */ + FEAT_RAM_HEAP_USED(6), + + /** + * Max amount of non-heap RAM metrics supported + */ + FEAT_RAM_NON_HEAP_MAX(7), + + /** + * Used amount of non-heap RAM metrics supported + */ + FEAT_RAM_NON_HEAP_USED(8), + + /** + * Launch arguments metrics supported + */ + FEAT_LAUNCH_ARGS(9), + + /** + * Server uptime metrics supported + */ + FEAT_UPTIME(10), + + /** + * Player metrics supported + */ + FEAT_PLAYERS_LIST(11), + + /** + * World metrics supported + */ + FEAT_WORLDS_LIST(12), + + /** + * Logs upload supported + */ + FEAT_LOGS(13), + + /** + * I/O write speed metrics supported + */ + FEATS_IO_WRITE(14), + + /** + * I/O read speed metrics supported + */ + FEATS_IO_READ(15); + + /** + * Array containing all the cryptographic algorithms that are supported by default in this version + */ + public static final Capability[] DEFAULT_CRYPTO_ALGOS = new Capability[]{ + NO_CRYPTO, + CRYPTO_EXCH_RSA2048, + CRYPTO_EXCH_RSA4096, + CRYPTO_EXCH_DH2048, + CRYPTO_EXCH_DH4096, + CRYPTO_EXCH_ECDHP256, + CRYPTO_EXCH_ECDHP384, + CRYPTO_SYMM_AES128GCM, + CRYPTO_SYMM_AES256GCM, + CRYPTO_SYMM_CHACHA20POLY1305 + }; + + /** + * Array containing all the features that are supported by default in this version + */ + public static final Capability[] DEFAULT_FEATURES = new Capability[]{ + FEAT_OS, + FEAT_CPU_ARCH, + FEAT_JRE_VERSION, + FEAT_JVM_CORES, + FEAT_CPU_USAGE, + FEAT_RAM_HEAP_MAX, + FEAT_RAM_HEAP_USED, + FEAT_RAM_NON_HEAP_MAX, + FEAT_RAM_NON_HEAP_USED, + FEAT_LAUNCH_ARGS, + FEAT_UPTIME, + FEAT_PLAYERS_LIST, + FEAT_WORLDS_LIST, + FEAT_LOGS, + FEATS_IO_WRITE, + FEATS_IO_READ + }; + + /** + * Array containing the order of preference for the cryptographic algorithms to use for the key exchange + * + * @implNote The higher an element is in the array, the most preferred it is + */ + public static final Capability[] CRYPTO_EXCH_PREFERENCES = new Capability[]{ + CRYPTO_EXCH_ECDHP384, + CRYPTO_EXCH_ECDHP256, + CRYPTO_EXCH_DH4096, + CRYPTO_EXCH_DH2048, + CRYPTO_EXCH_RSA4096, + CRYPTO_EXCH_RSA2048, + NO_CRYPTO + }; + + /** + * Array containing the order of preference for the cryptographic algorithms to use for encryption + * + * @implNote The higher an element is in the array, the most preferred it is + */ + public static final Capability[] CRYPTO_SYMM_PREFERENCES = new Capability[]{ + CRYPTO_SYMM_AES256GCM, + CRYPTO_SYMM_CHACHA20POLY1305, + CRYPTO_SYMM_AES128GCM + }; + + /** + * Bit index for BeaconCapability + */ + public final int bitIndex; + + /** + * Attributes a bit index to the capability being created + * + * @param bitIndex Bit index + */ + Capability(int bitIndex) { + if(bitIndex < -1 || bitIndex >= FeatCapability.BITMAP_MAX_BITS) + { + throw new IllegalArgumentException("Unacceptable bit index"); + } + this.bitIndex = bitIndex; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/cap/CryptoCapability.java b/mods/common/src/main/java/me/peteras17/beacon/cap/CryptoCapability.java new file mode 100644 index 0000000000000000000000000000000000000000..ceb6832699ff247988953524899cfd6d7be8b698 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/cap/CryptoCapability.java @@ -0,0 +1,66 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + + +import java.math.BigInteger; + +public class CryptoCapability extends FeatCapability { + + /** + * Sets the cryptographic generation for this capability + * + * @param generation Generation to set + */ + public void setCryptoGen(CryptoGen generation) { + byte bits = (byte) generation.ordinal(); + for (int i = 0; i < 8; ++i) { + byte power = (byte) (1 << i); + if ((bits & power) == power) { + this.bitmap = this.bitmap.setBit(i); + } + } + } + + /** + * Gets the cryptographic generation set in this capability + * + * @return The currently-set cryptographic generation + */ + public CryptoGen getCryptoGen() { + BigInteger maskedGen = this.bitmap.and(new BigInteger(new byte[]{CryptoGen.GEN_MASK})); + return CryptoGen.of(maskedGen.intValue()); + } + + @Override + public ICapability copy() { + CryptoCapability copy = new CryptoCapability(); + copy.bitmap = bitmap; + return copy; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/cap/CryptoGen.java b/mods/common/src/main/java/me/peteras17/beacon/cap/CryptoGen.java new file mode 100644 index 0000000000000000000000000000000000000000..b9910fa07b1be06fcd491dfbb2a7c256e4e1f1d3 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/cap/CryptoGen.java @@ -0,0 +1,66 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + +/** + * Enumeration of the accepted cryptographic generations + */ +public enum CryptoGen { + + /** + * Legacy cryptographic generation - no encryption or key exchange + */ + LEGACY, + + /** + * Current cryptographic generation - both encryption and key exchange accepted + */ + CURRENT; + + + /** + * Mask to use to limit against the possible generation bits + */ + public static final int GEN_MASK = 0b11; + + /** + * Retrieves the cryptographic generation with the value provided + * + * @param val Value to look for + * @return Enum entry if found, null if not found + */ + public static CryptoGen of(int val) { + for (CryptoGen gen : CryptoGen.values()) { + if (gen.ordinal() == val) { + return gen; + } + } + + return null; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/cap/FeatCapability.java b/mods/common/src/main/java/me/peteras17/beacon/cap/FeatCapability.java new file mode 100644 index 0000000000000000000000000000000000000000..eb3bda64406889aa86e890205cc8b2fda108393a --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/cap/FeatCapability.java @@ -0,0 +1,134 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + +import java.math.BigInteger; + +public class FeatCapability implements ICapability { + + /** + * Maximum number of bits in Beacon's capability bitmaps + */ + public static final int BITMAP_MAX_BITS = 128; + + /** + * Maximum number of bytes in Beacon's capability bitmaps + */ + public static final int BITMAP_MAX_BYTES = BITMAP_MAX_BITS / 8; + + /** + * Bitmap instance to store bits in + */ + protected BigInteger bitmap; + + /** + * Create a new capability bitmap for Beacon + */ + public FeatCapability() { + bitmap = BigInteger.ZERO; + } + + @Override + public void enable(Capability capability) { + if (capability != Capability.ALWAYS_ACTIVE) { + bitmap = bitmap.setBit(capability.bitIndex); + } + } + + @Override + public void enable(Capability[] capabilities) { + for (Capability cap : capabilities) { + enable(cap); + } + } + + public void disable(Capability capability) { + if (capability != Capability.ALWAYS_ACTIVE) { + bitmap = bitmap.clearBit(capability.bitIndex); + } + } + + public boolean supports(Capability capability) { + if (capability == Capability.ALWAYS_ACTIVE) { + return true; + } + return bitmap.testBit(capability.bitIndex); + } + + @Override + public boolean supports(int bit) { + return bitmap.testBit(bit); + } + + @Override + public boolean equals(ICapability other) { + for (int i = 0; i < BITMAP_MAX_BITS; ++i) { + // Stop at first non-equal bit + if (other.supports(i) ^ this.supports(i)) { + return false; + } + } + + return true; + } + + @Override + public void intersect(ICapability other) { + for (int i = 0; i < BITMAP_MAX_BITS; ++i) { + // Clear all not in-common bits + if (!(other.supports(i) && this.supports(i))) { + this.bitmap = this.bitmap.clearBit(i); + } + } + } + + @Override + public byte[] exportPayload() { + byte[] outBuffer = new byte[BITMAP_MAX_BYTES]; + byte[] bmpArray = bitmap.toByteArray(); + + // Copy all bytes, one by one, to the output buffer + for (int bmpIndex = 0, outIndex = outBuffer.length - bmpArray.length; outIndex < outBuffer.length; bmpIndex++, outIndex++) { + outBuffer[outIndex] = bmpArray[bmpIndex]; + } + + return outBuffer; + } + + @Override + public void importPayload(byte[] payload) { + bitmap = new BigInteger(payload); + } + + @Override + public ICapability copy() { + FeatCapability copy = new FeatCapability(); + copy.bitmap = bitmap; + return copy; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/cap/ICapability.java b/mods/common/src/main/java/me/peteras17/beacon/cap/ICapability.java new file mode 100644 index 0000000000000000000000000000000000000000..e3b8999261ae4522e885ca441d74674e9026a3bb --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/cap/ICapability.java @@ -0,0 +1,109 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + +/** + * Capability manager interface + */ +public interface ICapability { + + /** + * Enable a specific capability + * + * @param capability Capability to enable + */ + void enable(Capability capability); + + /** + * Enables multiple capabilities at once + * + * @param capabilities Capabilities to enable + */ + void enable(Capability[] capabilities); + + /** + * Disable a specific capability + * + * @param capability Capability to disable + */ + @SuppressWarnings("unused") + void disable(Capability capability); + + /** + * Checks whether the provided capability is enabled + * + * @param capability Capability to check + * @return True if enabled, false if not + */ + boolean supports(Capability capability); + + /** + * Checks whether the provided bit is enabled + * + * @param bit Bit to check + * @return True if enabled, false if not + * @apiNote Please prefer .supports(Capability) + */ + boolean supports(int bit); + + /** + * Checks whether this object's bitmap is entirely equal to another object's + * + * @return True if they're equal, false if not + */ + boolean equals(ICapability other); + + /** + * Intersects all supported capabilities between this object and another object's. + * After call, this object's bitmap will be the intersection of both objects + * + * @param other Other capability object + */ + void intersect(ICapability other); + + /** + * Converts a 128-long byte array into a capability bitmap + * + * @param payload Array, big-endian + */ + void importPayload(byte[] payload); + + /** + * Formats this capability bitmap into a 128-long byte array + * + * @return Array, big-endian + */ + byte[] exportPayload(); + + /** + * Returns a copy of this capability object + * + * @return A copy + */ + ICapability copy(); +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/cmd/Command.java b/mods/common/src/main/java/me/peteras17/beacon/cmd/Command.java index 380e077ba4979cec182da43f420c74f709b92396..70c080126c7655f1dd4b532ca2cf65218d4e190a 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/cmd/Command.java +++ b/mods/common/src/main/java/me/peteras17/beacon/cmd/Command.java @@ -1,3 +1,30 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 18/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.cmd; import java.util.LinkedList; @@ -13,7 +40,7 @@ public class Command { * Command name */ private final String name; - + /** * List of subcommands this command accepts */ @@ -32,13 +59,13 @@ public class Command { /** * Creates a new root command. Name is automatically converted to lower-case - * @param name Command name for Beacon mod users to use + * + * @param name Command name for Beacon mod users to use * @param callback Callback function to execute the command. * Argument is always of type com.mojang.brigadier.context.CommandContext. * Returns the execution result */ - public Command(String name, Function callback) - { + public Command(String name, Function callback) { this.name = name.toLowerCase(); this.callback = callback; this.subcommands = new LinkedList<>(); @@ -47,33 +74,34 @@ public class Command { /** * Creates a subcommand. Name is automatically converted to lower-case - * @param name Command name for Beacon mod users to use + * + * @param name Command name for Beacon mod users to use * @param callback Callback function to execute the command. * Argument is always of type com.mojang.brigadier.context.CommandContext. * Returns the execution result - * @param parent Subcommand's parent + * @param parent Subcommand's parent */ - private Command(String name, Function callback, Command parent) - { + private Command(String name, Function callback, Command parent) { this(name, callback); - - if(null != parent) { + + if (null != parent) { this.root = parent.root; - } + } } /** * Returns this command's name + * * @return The command's name */ - public String getName() - { + public String getName() { return name; } /** * Creates a new subcommand for this command - * @param name Command name for Beacon mod users to use + * + * @param name Command name for Beacon mod users to use * @param callback Callback function to execute the command. * Argument is always of type com.mojang.brigadier.context.CommandContext. * Returns the execution result @@ -81,13 +109,11 @@ public class Command { * @throws IllegalArgumentException Thrown if another subcommand with the same name already exists */ @SuppressWarnings("unused") // Used in server-specific code - public Command appendSubcommand(String name, Function callback) throws IllegalArgumentException - { - if(subcommands.stream().anyMatch(c -> c.getName().equalsIgnoreCase(name))) - { + public Command appendSubcommand(String name, Function callback) throws IllegalArgumentException { + if (subcommands.stream().anyMatch(c -> c.getName().equalsIgnoreCase(name))) { throw new IllegalArgumentException("Subcommand already exists!"); } - + Command command = new Command(name, callback, this); subcommands.add(command); return command; @@ -95,36 +121,37 @@ public class Command { /** * Returns whether this command can take arguments entered by the user + * * @return True if command can take arguments (no subcommands), false if not */ - public boolean takesArgs() - { + public boolean takesArgs() { return subcommands.isEmpty(); } /** * Retrieves a subcommand based on the given name + * * @param name Name of the subcommand to retrieve * @return Retrieved subcommand if found, null if not found */ @SuppressWarnings("unused") // Used in server-specific code - public Command getSubcommand(String name) - { + public Command getSubcommand(String name) { return subcommands.stream().filter(c -> c.name.equalsIgnoreCase(name)).findFirst().orElse(null); } /** * Returns all registered subcommands for this command + * * @return Array containing subcommands */ @SuppressWarnings("unused") // Used in server-specific code - public Command[] getSubcommands() - { + public Command[] getSubcommands() { return subcommands.toArray(new Command[0]); } /** * Executes this command + * * @param context Command execution context * @return Execution result */ diff --git a/mods/common/src/main/java/me/peteras17/beacon/cmd/CommonCommands.java b/mods/common/src/main/java/me/peteras17/beacon/cmd/CommonCommands.java index 863f35daee3ac45e422657d981e1e59313288b3a..4ee53d9265b3ba5f30be82fde6bbee2e1dd4aa7e 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/cmd/CommonCommands.java +++ b/mods/common/src/main/java/me/peteras17/beacon/cmd/CommonCommands.java @@ -1,3 +1,30 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 18/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.cmd; public class CommonCommands { diff --git a/mods/common/src/main/java/me/peteras17/beacon/cmd/ExecResult.java b/mods/common/src/main/java/me/peteras17/beacon/cmd/ExecResult.java index f29b063b4ac19bd71c2b67232b685eba2ab7e378..08eae19b275b6b07a3ecc5003869d170970b552f 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/cmd/ExecResult.java +++ b/mods/common/src/main/java/me/peteras17/beacon/cmd/ExecResult.java @@ -1,12 +1,40 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 09/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.cmd; import me.peteras17.beacon.BeaconStatus; /** * Contains a command execution result + * * @param status Execution status * @param result Execution result message if status == BeaconStatus.OK, or empty * Result is sent as a message to the entity running the command */ -public record ExecResult(BeaconStatus status, String result) { +public record ExecResult(BeaconStatus status, String result) { } diff --git a/mods/common/src/main/java/me/peteras17/beacon/data/ServerType.java b/mods/common/src/main/java/me/peteras17/beacon/data/ServerType.java new file mode 100644 index 0000000000000000000000000000000000000000..f70e95f498db85d95d9fb46436b943e60641a572 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/data/ServerType.java @@ -0,0 +1,50 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.data; + +/** + * Lists the server types + */ +@SuppressWarnings("unused") +public enum ServerType { + + /** + * Unknown type + */ + OTHER, + + /** + * Vanilla Minecraft server + */ + VANILLA, + + /** + * FabricMC server + */ + FABRIC +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/data/WorldWeather.java b/mods/common/src/main/java/me/peteras17/beacon/data/WorldWeather.java new file mode 100644 index 0000000000000000000000000000000000000000..f84049a8cee9530e18f8ef0f3a3456c22bd3ad87 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/data/WorldWeather.java @@ -0,0 +1,53 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.data; + +/** + * Lists the different weather types a world can have + */ +public enum WorldWeather { + /** + * Clear skies + */ + CLEAR, + + /** + * Simply raining + */ + RAINING, + + /** + * Thunderstorms roaring + */ + THUNDERSTORM, + + /** + * Unknown or custom weather + */ + OTHER +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/logs/Interceptor.java b/mods/common/src/main/java/me/peteras17/beacon/logs/Interceptor.java index 1241fb82fd5d4c20e7a8564d3735bfb77b41f00c..fcf82a433315c3092dce499bc05b590a65d1f20f 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/logs/Interceptor.java +++ b/mods/common/src/main/java/me/peteras17/beacon/logs/Interceptor.java @@ -1,5 +1,34 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 11/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.logs; +import me.peteras17.beacon.SocketManager; +import me.peteras17.beacon.socket.ops.Log; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LogEvent; @@ -31,6 +60,11 @@ public class Interceptor extends AbstractAppender { */ private final int _maxMessages; + /** + * Manager instance for the web socket that can be open + */ + private final SocketManager _socketMgr; + /** * Queue containing a set maximum number of logged events' messages */ @@ -38,20 +72,22 @@ public class Interceptor extends AbstractAppender { /** * Creates a new intercepting appender instance, and automatically attaches it + * * @param maxMessages Maximum number of messages to keep in the logs queue - * @param minLevel Minimum acceptable level (inclusive) of events to intercept + * @param minLevel Minimum acceptable level (inclusive) of events to intercept */ - public Interceptor(int maxMessages, Level minLevel) { + public Interceptor(int maxMessages, Level minLevel, SocketManager socketMgr) { super(APPENDER_NAME, null, null, false, null); _queue = new LinkedList<>(); _maxMessages = maxMessages; _minLevel = minLevel.intLevel(); + _socketMgr = socketMgr; // Get the different things we need LoggerContext logContext = (LoggerContext) LogManager.getContext(false); Configuration logConfig = logContext.getConfiguration(); LoggerConfig loggerConfig = logConfig.getRootLogger(); - + // Start and attach appender this.start(); logConfig.addAppender(this); @@ -61,30 +97,30 @@ public class Interceptor extends AbstractAppender { /** * Receives an event to append + * * @param event The LogEvent. */ @Override public void append(LogEvent event) { - + // Reject events not "strong" enough to intercept - if(event.getLevel().intLevel() > _minLevel) { - return; - } - - // Avoid overflowing the queue - if(_queue.size() >= _maxMessages) { - _queue.remove(); + if (event.getLevel().intLevel() <= _minLevel) { + // Avoid overflowing the queue + if (_queue.size() >= _maxMessages) { + _queue.remove(); + } + + // Save the intercepted log message + String msg = event.getMessage().getFormattedMessage(); + _queue.add(msg); } - - // Save the intercepted log message - _queue.add(event.getMessage().getFormattedMessage()); - } - /** - * Exports the last n logged events' messages - * @return Messages logged - */ - public String[] getLogs() { - return _queue.toArray(new String[0]); + // Send all logs in queue if possible + if (!_queue.isEmpty()) { + // Make sure the logs were sent before clearing the queue + if(_socketMgr.sendOp(new Log(String.join("\n", _queue)))) { + _queue.clear(); + } + } } } \ No newline at end of file diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetric.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetric.java index 1d5ab0ac8ec511e76165ff277400bfcd65bb137a..f6e48e38c63b9b696c489681ecd016f004236a41 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetric.java +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetric.java @@ -1,8 +1,35 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 22/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.metrics; import com.fasterxml.jackson.databind.node.ObjectNode; -import me.peteras17.beacon.Capability; -import me.peteras17.beacon.CapabilityManager; +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.cap.ICapability; /** * Beacon metric interface @@ -12,31 +39,36 @@ public interface IMetric { /** * Returns this metric instance's type + * * @return Metric type */ MetricType getType(); /** * Returns this metric instance's name (metric type name) + * * @return Metric name */ String getName(); /** * Returns the capability the other party must support in order to use this metric + * * @return Capability value */ Capability getNeededCapability(); /** * Serializes this object into a JSON object node - * @param on Object node to use to serialize this object into + * + * @param on Object node to use to serialize this object into * @param capMgr Capability manager instance, allowing function to know whether to serialize or not */ - void serialize(ObjectNode on, CapabilityManager capMgr); + void serialize(ObjectNode on, ICapability capMgr); /** * Checks whether this metric or any metric contained within this one is of the provided type + * * @param metricType Type to look for * @return Null if not found, metric instance if found */ diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetricProvider.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetricProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..9cd0ade3f96bc53cc6f806be31f3e183f5e962f6 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/IMetricProvider.java @@ -0,0 +1,51 @@ +/* + * Beacon server-side mod source + * + * @author : PS-HEIG + * @created : 28/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics; + +/** + * Common interface for all metric providers + */ +public interface IMetricProvider { + + /** + * Registers this provider to the provided root group + * + * @param rootGroup Group to register provider to + * @throws IllegalArgumentException Raised in case the metric type of + * the metrics that the provider tried + * to register already exists in the group + */ + void register(MetricGroup rootGroup) throws IllegalArgumentException; + + /** + * Makes the provider stop loading new metrics, if possible + * + * @apiNote Useful mostly for providers that manage threads + */ + void stop(); +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/MemoryMetrics.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/MemoryMetrics.java deleted file mode 100644 index 2143dbbf154a0a2a26abf21168ab3185bf94c47a..0000000000000000000000000000000000000000 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/MemoryMetrics.java +++ /dev/null @@ -1,50 +0,0 @@ -package me.peteras17.beacon.metrics; - -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; - -/** - * Class to retrieve memory-related metrics - */ -public class MemoryMetrics { - - /** - * Memory bean, used to retrieve memory-related information - */ - MemoryMXBean _memoryBean; - - /** - * Default constructor - */ - public MemoryMetrics() - { - _memoryBean = ManagementFactory.getMemoryMXBean(); - } - - /** - * Returns the number of free bytes of heap memory - * @return Free bytes - */ - public long getHeapFree() - { - return _memoryBean.getHeapMemoryUsage().getMax() - _memoryBean.getHeapMemoryUsage().getUsed(); - } - - /** - * Returns the number of used bytes of heap memory - * @return Used bytes - */ - public long getHeapUsed() - { - return _memoryBean.getHeapMemoryUsage().getUsed(); - } - - /** - * Returns the maximum number of bytes of heap memory - * @return Maximum bytes - */ - public long getHeapMax() - { - return _memoryBean.getHeapMemoryUsage().getMax(); - } -} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricCollection.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricCollection.java index 72c84c5f42ef802f9e45d3a730db9374b063437f..332f9a563ebbf40130bc834af5f60fc6f3cf6978 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricCollection.java +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricCollection.java @@ -1,8 +1,35 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 22/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.metrics; import com.fasterxml.jackson.databind.node.ObjectNode; -import me.peteras17.beacon.Capability; -import me.peteras17.beacon.CapabilityManager; +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.cap.ICapability; import java.util.LinkedList; import java.util.List; @@ -31,16 +58,17 @@ public class MetricCollection implements IMetric { /** * Creates a new metric collection, which acts like a JSON list of sets + * * @param metricType Metric type represented by this instance * @param capability Capability needed in order to serialize this object - * @param callback Callback used to retrieve the list of sets + * @param callback Callback used to retrieve the list of sets */ public MetricCollection(MetricType metricType, Capability capability, Supplier> callback) { this.metricType = metricType; this.capability = capability; this.callback = callback; } - + @Override public MetricType getType() { return metricType; @@ -57,28 +85,27 @@ public class MetricCollection implements IMetric { } @Override - public void serialize(ObjectNode on, CapabilityManager capMgr) { + public void serialize(ObjectNode on, ICapability capMgr) { // Ignore call if unsupported - if(!capMgr.supports(capability)) + if (!capMgr.supports(capability)) return; // Check if any other IMetrics are inside the received list List parsedList = new LinkedList<>(); - - for(Object obj : callback.get()) { - if(obj instanceof IMetric) { + + for (Object obj : callback.get()) { + if (obj instanceof IMetric) { // Serialize any metrics inside ObjectNode innerNode = on.objectNode(); ((IMetric) obj).serialize(innerNode, capMgr); parsedList.add(innerNode); - } - else { + } else { // Otherwise, just add them as-is parsedList.add(obj); } } - + on.putPOJO(getName(), parsedList); } diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricGroup.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricGroup.java index eac2999ac750bf00e47eb324bc8924958afd3213..c33636117ab8b8176d1d4bb29c1480246ab37a9f 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricGroup.java +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricGroup.java @@ -1,8 +1,35 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 22/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.metrics; import com.fasterxml.jackson.databind.node.ObjectNode; -import me.peteras17.beacon.Capability; -import me.peteras17.beacon.CapabilityManager; +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.cap.ICapability; import java.util.ArrayList; import java.util.List; @@ -27,29 +54,56 @@ public class MetricGroup implements IMetric { */ private final MetricType metricType; + /** + * Does this metric group need a node? + */ + private final boolean needsNode; + + /** * Creates a new group of metrics + * * @param metricType Metric type represented by this object * @param capability Capability needed to serialize this object + * @param needsNode Does this group need a node? Value to False is useful if not is a list item */ - public MetricGroup(MetricType metricType, Capability capability) { + public MetricGroup(MetricType metricType, Capability capability, boolean needsNode) { metrics = new ArrayList<>(); this.capability = capability; this.metricType = metricType; + this.needsNode = needsNode; } - - public void addMetric(IMetric metric) { - - // Check for duplicated metric types between what we have and what the other metric has - for(MetricType metricType : MetricType.values()) { - if(null != findMetric(metricType) && null != metric.findMetric(metricType)) { - throw new IllegalArgumentException(String.format("Metric type %s is duplicate", metricType.name())); + + /** + * Creates a new group of metrics + * + * @param metricType Metric type represented by this object + * @param capability Capability needed to serialize this object + */ + public MetricGroup(MetricType metricType, Capability capability) { + this(metricType, capability, true); + } + + /** + * Adds a new metric to this metric group + * + * @param metric Metric to add to the group + * @throws IllegalArgumentException Raised in case type of provided metric already exists + * @apiNote Thread-safe code + */ + public void addMetric(IMetric metric) throws IllegalArgumentException { + synchronized (metrics) { + // Check for duplicated metric types between what we have and what the other metric has + for (MetricType metricType : MetricType.values()) { + if (null != findMetric(metricType) && null != metric.findMetric(metricType)) { + throw new IllegalArgumentException(String.format("Metric type %s is duplicate", metricType.name())); + } } - } - metrics.add(metric); + metrics.add(metric); + } } - + @Override public MetricType getType() { return metricType; @@ -66,34 +120,44 @@ public class MetricGroup implements IMetric { } @Override - public void serialize(ObjectNode on, CapabilityManager capMgr) { + public void serialize(ObjectNode on, ICapability capMgr) { // Ignore call if unsupported - if(!capMgr.supports(capability)) + if (!capMgr.supports(capability)) return; - + // Serialize every metric inside - ObjectNode innerNode = on.withObject(getName()); - for(IMetric metric : metrics) { - metric.serialize(innerNode, capMgr); + synchronized (metrics) { + + // Only create a node if needed + ObjectNode innerNode = on; + if (needsNode) { + innerNode = on.withObject(getName()); + } + + for (IMetric metric : metrics) { + metric.serialize(innerNode, capMgr); + } } } @Override public IMetric findMetric(MetricType metricType) { - if(getType() == metricType) { + if (getType() == metricType) { return this; } // Check every inner metric for the type IMetric foundMetric = null; - for(IMetric metric : metrics) { - foundMetric = metric.findMetric(metricType); - if(foundMetric != null) { - break; + synchronized (metrics) { + for (IMetric metric : metrics) { + foundMetric = metric.findMetric(metricType); + if (foundMetric != null) { + break; + } } } - + return foundMetric; } } diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricMap.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricMap.java index 01365a2fc69cad7e086b5eea796d2c5ce6e9d15a..f7dbdd435beefd08fd7fa66b59ad5f914888fbe2 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricMap.java +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricMap.java @@ -1,8 +1,35 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 22/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.metrics; import com.fasterxml.jackson.databind.node.ObjectNode; -import me.peteras17.beacon.Capability; -import me.peteras17.beacon.CapabilityManager; +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.cap.ICapability; import java.util.Map; import java.util.function.Supplier; @@ -30,16 +57,17 @@ public class MetricMap implements IMetric { /** * Creates a new metrics map, acting as a JSON set + * * @param metricType Type of metrics contained inside this object * @param capability Capability needed to serialize this object - * @param callback Callback to retrieve the set's values + * @param callback Callback to retrieve the set's values */ public MetricMap(MetricType metricType, Capability capability, Supplier> callback) { this.metricType = metricType; this.capability = capability; this.callback = callback; } - + @Override public String getName() { return getType().name(); @@ -51,12 +79,12 @@ public class MetricMap implements IMetric { } @Override - public void serialize(ObjectNode on, CapabilityManager capMgr) { + public void serialize(ObjectNode on, ICapability capMgr) { // Ignore call if unsupported - if(!capMgr.supports(capability)) + if (!capMgr.supports(capability)) return; - + // Serialize every entry in the set ObjectNode setNode = on.withObject(getName()); for (Map.Entry setEntry : callback.get().entrySet()) { diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricNode.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricNode.java index a12665701a663722c5fe5fbb818d3a4084ad40f9..72a5cf063f5f3e383cd9508e69f9a289ba82b718 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricNode.java +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricNode.java @@ -1,8 +1,35 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 22/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.metrics; import com.fasterxml.jackson.databind.node.ObjectNode; -import me.peteras17.beacon.Capability; -import me.peteras17.beacon.CapabilityManager; +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.cap.ICapability; import java.util.function.Supplier; @@ -28,16 +55,17 @@ public class MetricNode implements IMetric { /** * Creates a new metric node + * * @param metricType Metric type represented by this node * @param capability Capability needed to serialize this node - * @param callback Callback used to retrieve this node's value + * @param callback Callback used to retrieve this node's value */ public MetricNode(MetricType metricType, Capability capability, Supplier callback) { this.metricType = metricType; this.capability = capability; this.callback = callback; } - + @Override public String getName() { return getType().name(); @@ -49,12 +77,12 @@ public class MetricNode implements IMetric { } @Override - public void serialize(ObjectNode on, CapabilityManager capMgr) { - + public void serialize(ObjectNode on, ICapability capMgr) { + // Ignore call if unsupported - if(!capMgr.supports(capability)) + if (!capMgr.supports(capability)) return; - + on.putPOJO(getName(), callback.get()); } diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricType.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricType.java index 6053a32192894bf0de64826808a8d30780eb52d1..b9e0e261e59d5e67a80494839e608412f24115c8 100644 --- a/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricType.java +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/MetricType.java @@ -1,20 +1,47 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 09/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.metrics; /** * An enumeration of all supported metric types */ public enum MetricType { - + /* * Root category */ - + ROOT, - + /* * Group categories */ - + MOD, HOST, SERVER, @@ -26,56 +53,66 @@ public enum MetricType { PROPERTIES, PLAYERS, WORLDS, + DIMENSIONS, GAME_RULES, - + TIMESTAMP, + /* * Metric names */ - + MOD_VERSION, MOD_SERVER_ID, MOD_SERVER_NAME, - + OS_NAME, OS_VERSION, - + HEAP_FREE, HEAP_USED, HEAP_MAX, NON_HEAP_FREE, NON_HEAP_USED, NON_HEAP_MAX, - + CPU_ARCH, CPU_USAGE, CPU_CORES, - + WRITE_SPEED, READ_SPEED, - + IO_DELAY, + JVM_ARGS, JRE_VERSION, - + SERVER_TYPE, SERVER_MINECRAFT_VERSION, SERVER_PLAYER_COUNT, SERVER_MAX_PLAYER_COUNT, SERVER_UPTIME, SERVER_MOTD, - + PLAYER_GUID, PLAYER_USERNAME, PLAYER_SESSION_PLAYTIME, PLAYER_TOTAL_PLAYTIME, PLAYER_IS_OP, - PLAYER_POSITION, + PLAYER_POS_X, + PLAYER_POS_Y, + PLAYER_POS_Z, PLAYER_HEALTH, PLAYER_HUNGER, + PLAYER_SATURATION, PLAYER_XP, - - WORLD_GUID, + + WORLD_NAME, WORLD_TYPE, + WORLD_DIFFICULTY, + WORLD_IS_HARDCORE, WORLD_TIME, WORLD_WEATHER, - WORLD_SPAWN + WORLD_SPAWN_X, + WORLD_SPAWN_Y, + WORLD_SPAWN_Z } diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Host.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Host.java new file mode 100644 index 0000000000000000000000000000000000000000..f5af07f28f132438339a9f7f580fba27216cc575 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Host.java @@ -0,0 +1,71 @@ +/* + * Beacon server-side mod source + * + * @author : PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricType; + +/** + * Provider for host machine-related metrics + */ +public class Host implements IMetricProvider { + + /** + * Metrics group + */ + private final MetricGroup _hostMetrics; + private final IO _io = new IO(); + + /** + * Create a mod metrics provider + */ + public Host() { + _hostMetrics = new MetricGroup(MetricType.HOST, Capability.ALWAYS_ACTIVE); + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + + // Instantiate and add all mod metrics + new Memory().register(_hostMetrics); + new OperatingSystem().register(_hostMetrics); + new JVM().register(_hostMetrics); + new Processor().register(_hostMetrics); + _io.register(_hostMetrics); + + // Add this metric group + rootGroup.addMetric(_hostMetrics); + } + + @Override + public void stop() { + _io.stop(); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/IO.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/IO.java new file mode 100644 index 0000000000000000000000000000000000000000..7a00913906a097197979562a407c66e2ce47bdb5 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/IO.java @@ -0,0 +1,236 @@ +/* + * Beacon server-side mod source + * + * @author : PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Random; + +/** + * Class to retrieve I/O-related metrics + */ +class IO implements IMetricProvider { + + /** + * Name to use for the I/O delay estimation thread + */ + private final static String THREAD_NAME = "Beacon I/O thread"; + + /** + * Number of milliseconds to wait between polls + */ + private final static int THREAD_POLL_INTERVAL = 60000; + + /** + * Number of nanoseconds in a second + */ + private final static double ONE_SEC_IN_NS = 1000000000.0; + + /** + * Number of bytes in the I/O buffer + */ + private final static int IO_BUFFER_SIZE = 1024 * 1024; + + /** + * Metrics group + */ + private final MetricGroup _ioGroup; + + /** + * Thread instance + */ + private final Thread _thread; + + /** + * Buffer that will contain the data that will be written into and read from the temporary file + */ + @SuppressWarnings("unused") + private final byte[] _ioBuffer; + + /** + * Random data provider + */ + private final Random _random; + + /** + * Time needed to perform the last file access, in nanoseconds + */ + private double _lastAccessTime; + + /** + * Last measured write speed, in bytes per second + */ + private double _lastWriteSpeed; + + /** + * Last measured read speed, in bytes per second + */ + private double _lastReadSpeed; + + /** + * Default constructor + */ + IO() { + _ioBuffer = new byte[IO.IO_BUFFER_SIZE]; + _random = new Random(); + _ioGroup = new MetricGroup(MetricType.IO, Capability.ALWAYS_ACTIVE); + _thread = new Thread(this::threadEntrypoint); + + // Setup thread + _thread.setDaemon(true); + _thread.setName(IO.THREAD_NAME); + _thread.setPriority(Thread.MAX_PRIORITY); + _thread.start(); + } + + private void threadEntrypoint() { + // Get .jar's directory, so the temporary file is created there + String libPath = ManagementFactory.getRuntimeMXBean().getSystemProperties().get("user.dir"); + Path serverDir = Path.of(libPath); + long accessStartTime, accessEndTime; + long writeStartTime, writeEndTime; + long readStartTime, readEndTime; + + /* Controlled infinite loop */ + while (!Thread.interrupted()) { + + // Make it thread-safe :) + synchronized (_ioBuffer) { + + // Generate new random data + _random.nextBytes(_ioBuffer); + + File tmpFile; + try { + // Measure time needed to open file + accessStartTime = System.nanoTime(); + tmpFile = Files.createTempFile(serverDir, ".", ".tmp").toFile(); + try (FileOutputStream fos = new FileOutputStream(tmpFile, false); + BufferedOutputStream bos = new BufferedOutputStream(fos, IO.IO_BUFFER_SIZE)) { + bos.flush(); + accessEndTime = System.nanoTime(); + + // Perform write + writeStartTime = System.nanoTime(); + bos.write(_ioBuffer); + bos.flush(); + writeEndTime = System.nanoTime(); + } catch (IOException ignored) { + // In case on an error, make result invalid + writeEndTime = writeStartTime = 0; + accessEndTime = accessStartTime; + } + + try (FileInputStream fis = new FileInputStream(tmpFile); + BufferedInputStream bis = new BufferedInputStream(fis, IO.IO_BUFFER_SIZE)) { + // Perform read + readStartTime = System.nanoTime(); + if (-1 == bis.read(_ioBuffer, 0, IO.IO_BUFFER_SIZE)) { + throw new IOException(); + } + readEndTime = System.nanoTime(); + } catch (IOException ignored) { + // In case on an error, make result invalid + readEndTime = readStartTime = 0; + } + + } catch (IOException e) { + throw new RuntimeException(e); + } + + //noinspection ResultOfMethodCallIgnored + tmpFile.delete(); + + // Calculate speeds + _lastAccessTime = accessEndTime - accessStartTime; + + // May cause division by 0 if unchecked + if ((writeEndTime - writeStartTime) > 0) { + _lastWriteSpeed = IO.IO_BUFFER_SIZE / ((writeEndTime - writeStartTime) / IO.ONE_SEC_IN_NS); // Divide by 1s in ns + } else { + _lastWriteSpeed = 0; + } + + // May cause division by 0 if unchecked + if ((readEndTime - readStartTime) > 0) { + _lastReadSpeed = IO.IO_BUFFER_SIZE / ((readEndTime - readStartTime) / IO.ONE_SEC_IN_NS); // Divide by 1s in ns + } else { + _lastReadSpeed = 0; + } + } + + try { + //noinspection BusyWait + Thread.sleep(IO.THREAD_POLL_INTERVAL); + } catch (InterruptedException ignored) { + break; + } + } + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + _ioGroup.addMetric(new MetricNode(MetricType.READ_SPEED, Capability.FEATS_IO_READ, () -> { + synchronized (_ioBuffer) { + return _lastReadSpeed; + } + })); + _ioGroup.addMetric(new MetricNode(MetricType.WRITE_SPEED, Capability.FEATS_IO_WRITE, () -> { + synchronized (_ioBuffer) { + return _lastWriteSpeed; + } + })); + _ioGroup.addMetric(new MetricNode(MetricType.IO_DELAY, Capability.ALWAYS_ACTIVE, () -> { + synchronized (_ioBuffer) { + return _lastAccessTime; + } + })); + + // Append group to root + rootGroup.addMetric(_ioGroup); + } + + + @Override + public void stop() { + try { + _thread.interrupt(); + _thread.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/JVM.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/JVM.java new file mode 100644 index 0000000000000000000000000000000000000000..21dde37fe44bd9f0a642383bf5013aec49af25d7 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/JVM.java @@ -0,0 +1,74 @@ +/* + * Beacon server-side mod source + * + * @author : PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; + +/** + * Class to retrieve JVM-related metrics + */ +class JVM implements IMetricProvider { + + /** + * Metrics group + */ + private final MetricGroup _jvmGroup; + + /** + * Memory bean, used to retrieve memory-related information + */ + private final RuntimeMXBean _rtBean; + + /** + * Default constructor + */ + JVM() { + _jvmGroup = new MetricGroup(MetricType.JVM, Capability.ALWAYS_ACTIVE); + _rtBean = ManagementFactory.getRuntimeMXBean(); + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + _jvmGroup.addMetric(new MetricNode(MetricType.JVM_ARGS, Capability.FEAT_LAUNCH_ARGS, _rtBean::getInputArguments)); + _jvmGroup.addMetric(new MetricNode(MetricType.JRE_VERSION, Capability.FEAT_JRE_VERSION, _rtBean::getVmVersion)); + + // Append group to root + rootGroup.addMetric(_jvmGroup); + } + + @Override + public void stop() { + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Memory.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Memory.java new file mode 100644 index 0000000000000000000000000000000000000000..3a0481d6a46a7d0c587a9dd16701ac1bedb917bf --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Memory.java @@ -0,0 +1,110 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 13/07/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; + +/** + * Class to retrieve memory-related metrics + */ +class Memory implements IMetricProvider { + + /** + * Metrics group + */ + private final MetricGroup _memoryGroup; + + /** + * Memory bean, used to retrieve memory-related information + */ + private final MemoryMXBean _memoryBean; + + /** + * Default constructor + */ + Memory() { + _memoryGroup = new MetricGroup(MetricType.RAM, Capability.ALWAYS_ACTIVE); + _memoryBean = ManagementFactory.getMemoryMXBean(); + } + + /** + * Returns the number of free bytes of heap memory + * + * @return Free bytes + */ + private long getHeapFree() { + long max = _memoryBean.getHeapMemoryUsage().getMax(); + long used = _memoryBean.getHeapMemoryUsage().getUsed(); + + if (max == -1 || used == -1) { + return -1; + } + + return max - used; + } + + /** + * Returns the number of free bytes of non-heap memory + * + * @return Free bytes + */ + private long getNonHeapFree() { + long max = _memoryBean.getNonHeapMemoryUsage().getMax(); + long used = _memoryBean.getNonHeapMemoryUsage().getUsed(); + + if (max == -1 || used == -1) { + return -1; + } + + return max - used; + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + _memoryGroup.addMetric(new MetricNode(MetricType.HEAP_FREE, Capability.ALWAYS_ACTIVE, this::getHeapFree)); + _memoryGroup.addMetric(new MetricNode(MetricType.HEAP_USED, Capability.FEAT_RAM_HEAP_USED, _memoryBean.getHeapMemoryUsage()::getUsed)); + _memoryGroup.addMetric(new MetricNode(MetricType.HEAP_MAX, Capability.FEAT_RAM_HEAP_MAX, _memoryBean.getHeapMemoryUsage()::getMax)); + _memoryGroup.addMetric(new MetricNode(MetricType.NON_HEAP_FREE, Capability.ALWAYS_ACTIVE, this::getNonHeapFree)); + _memoryGroup.addMetric(new MetricNode(MetricType.NON_HEAP_USED, Capability.FEAT_RAM_NON_HEAP_USED, _memoryBean.getNonHeapMemoryUsage()::getUsed)); + _memoryGroup.addMetric(new MetricNode(MetricType.NON_HEAP_MAX, Capability.FEAT_RAM_NON_HEAP_MAX, _memoryBean.getNonHeapMemoryUsage()::getMax)); + + // Append group to root + rootGroup.addMetric(_memoryGroup); + } + + @Override + public void stop() { + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Mod.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Mod.java new file mode 100644 index 0000000000000000000000000000000000000000..a67bab78700e1720c78b640e977a39bca786a4b3 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Mod.java @@ -0,0 +1,70 @@ +/* + * Beacon server-side mod source + * + * @author : PS-HEIG + * @created : 28/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +public class Mod implements IMetricProvider { + + /** + * Compiled mod's version + */ + public static final String VERSION = me.peteras17.beacon.ModVersion.VERSION; + + /** + * Metrics group + */ + private final MetricGroup _modMetrics; + + /** + * Create a mod metrics provider + */ + public Mod() { + _modMetrics = new MetricGroup(MetricType.MOD, Capability.ALWAYS_ACTIVE); + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + + // Instantiate and add all mod metrics + _modMetrics.addMetric(new MetricNode(MetricType.MOD_VERSION, Capability.ALWAYS_ACTIVE, () -> VERSION)); + _modMetrics.addMetric(new MetricNode(MetricType.MOD_SERVER_ID, Capability.ALWAYS_ACTIVE, () -> "TODO")); + _modMetrics.addMetric(new MetricNode(MetricType.MOD_SERVER_NAME, Capability.ALWAYS_ACTIVE, () -> "TODO")); + + // Add this metric group + rootGroup.addMetric(_modMetrics); + } + + @Override + public void stop() { + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/OperatingSystem.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/OperatingSystem.java new file mode 100644 index 0000000000000000000000000000000000000000..d10ed2054b2f2eac3027fdffd815ede20c4f395e --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/OperatingSystem.java @@ -0,0 +1,74 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; + +/** + * Class to retrieve memory-related metrics + */ +class OperatingSystem implements IMetricProvider { + + /** + * Metrics group + */ + private final MetricGroup _osGroup; + + /** + * Memory bean, used to retrieve memory-related information + */ + private final OperatingSystemMXBean _osBean; + + /** + * Default constructor + */ + OperatingSystem() { + _osGroup = new MetricGroup(MetricType.OS, Capability.FEAT_OS); + _osBean = ManagementFactory.getOperatingSystemMXBean(); + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + _osGroup.addMetric(new MetricNode(MetricType.OS_NAME, Capability.FEAT_OS, _osBean::getName)); + _osGroup.addMetric(new MetricNode(MetricType.OS_VERSION, Capability.FEAT_OS, _osBean::getVersion)); + + // Append group to root + rootGroup.addMetric(_osGroup); + } + + @Override + public void stop() { + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Processor.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Processor.java new file mode 100644 index 0000000000000000000000000000000000000000..43ffb3c577fd22d2ee50fac3db984f86651d5a4b --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Processor.java @@ -0,0 +1,93 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; + +/** + * Class to retrieve memory-related metrics + */ +class Processor implements IMetricProvider { + + /** + * Metrics group + */ + private final MetricGroup _cpuGroup; + + /** + * Memory bean, used to retrieve memory-related information + */ + private final OperatingSystemMXBean _osBean; + + /** + * Default constructor + */ + Processor() { + _cpuGroup = new MetricGroup(MetricType.CPU, Capability.ALWAYS_ACTIVE); + _osBean = ManagementFactory.getOperatingSystemMXBean(); + } + + /** + * Returns the current CPU load, clamped to value between 0 and 1 + * + * @return Load + */ + private double getCpuLoad() { + double usage = _osBean.getSystemLoadAverage() / _osBean.getAvailableProcessors(); + + // Clamp to 100% if load is too high, or 0 if not available + if (usage > 1.0) { + return 1.0; + } else if (usage < 0.0) { + return 0.0; + } + + return usage; + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + _cpuGroup.addMetric(new MetricNode(MetricType.CPU_ARCH, Capability.FEAT_CPU_ARCH, _osBean::getArch)); + _cpuGroup.addMetric(new MetricNode(MetricType.CPU_CORES, Capability.FEAT_JVM_CORES, _osBean::getAvailableProcessors)); + _cpuGroup.addMetric(new MetricNode(MetricType.CPU_USAGE, Capability.FEAT_CPU_USAGE, this::getCpuLoad)); + + // Append group to root + rootGroup.addMetric(_cpuGroup); + } + + @Override + public void stop() { + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Timestamp.java b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Timestamp.java new file mode 100644 index 0000000000000000000000000000000000000000..0af1b1936045e1487a079a86875416fe0995a23e --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/metrics/providers/Timestamp.java @@ -0,0 +1,48 @@ +/* + * Beacon server-side mod source + * + * @author : PS-HEIG + * @created : 28/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.metrics.providers; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; + +/** + * Timestamp metric provider + */ +public class Timestamp implements IMetricProvider { + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + rootGroup.addMetric(new MetricNode(MetricType.TIMESTAMP, Capability.ALWAYS_ACTIVE, () -> System.currentTimeMillis() / 1000)); + } + + @Override + public void stop() { + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/IOperation.java b/mods/common/src/main/java/me/peteras17/beacon/socket/IOperation.java new file mode 100644 index 0000000000000000000000000000000000000000..6142367d38957b355cdef9f6813ebfb001c0fd6a --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/IOperation.java @@ -0,0 +1,56 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket; + +/** + * Opreation object interface + */ +public interface IOperation { + + /** + * Returns this operation object's opcode + * + * @return Opcode corresponding to this object + */ + Opcode getOpcode(); + + /** + * Attempts to build this operation object from a given byte array payload + * + * @param payload Payload to use to build this operation object + * @throws IllegalArgumentException Thrown if payload cannot be used to create operation object + */ + void buildFrom(byte[] payload) throws IllegalArgumentException; + + /** + * Transforms this operation object into a byte array payload + * + * @return Payload to be sent across the network + */ + byte[] serialize(); +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/Opcode.java b/mods/common/src/main/java/me/peteras17/beacon/socket/Opcode.java new file mode 100644 index 0000000000000000000000000000000000000000..fe6690e33a8b4af557604adb2aa05710f3d9fd4b --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/Opcode.java @@ -0,0 +1,148 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket; + +/** + * List of supported opcodes + */ +public enum Opcode { + + /* ****************** / + * BENIGN RESPONSES * + / *******************/ + + /** + * No-Op opcode + */ + NOP(0x00), + + /** + * Acknowledgment opcode + */ + ACK(0x01), + + /* ****************** / + * HANDSHAKE PHASE * + / *******************/ + + /** + * Cryptographic algorithm exchange opcode + */ + CRY(0x10), + + /** + * Cryptographic algorithm selection opcode + */ + SEL(0x11), + + /** + * Key exchange opcode + */ + KEY(0x12), + + /** + * Feature exchange opcode + */ + CAP(0x13), + + /* ****************** / + * POST-HANDSHAKE * + / *******************/ + + /** + * Mod information opcode + */ + INF(0x20), + + /** + * Metrics opcode + */ + MTR(0x21), + + /** + * Logs opcode + */ + LOG(0x22), + + /** + * Command execution opcode + */ + CMD(0x23), + + /* ****************** / + * ERROR RESPONSES * + / *******************/ + + /** + * Retry request opcode + */ + RTY(0xFE), + + /** + * "Not OK" opcode + */ + NOK(0xFF); + + /** + * Opcode number + */ + public final byte opNbr; + + /** + * Creates a new opcode with the provided number + * + * @param opNbr Opcode number + */ + Opcode(int opNbr) { + this.opNbr = (byte) opNbr; + } + + /** + * Attempts to retrieve an opcode from the provided opcode byte + * + * @param opcode Opcode byte, used to find the Opcode equivalent + * @return Equivalent Opcode entry, if found + * @throws IllegalArgumentException Thrown if no correspondence found + */ + public static Opcode fromOp(byte opcode) throws IllegalArgumentException { + Opcode correspondence = null; + for (Opcode op : Opcode.values()) { + if (op.opNbr == opcode) { + correspondence = op; + break; + } + } + + // Throw error if not found + if (correspondence == null) { + throw new IllegalArgumentException("Unknown opcode"); + } + + return correspondence; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/SocketState.java b/mods/common/src/main/java/me/peteras17/beacon/socket/SocketState.java new file mode 100644 index 0000000000000000000000000000000000000000..f6ec252c547688b1830177b90d22c1d5de5ae671 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/SocketState.java @@ -0,0 +1,79 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket; + +/** + * Lists the different states the socket can find itself in + */ +public enum SocketState { + + /** + * Socket is in a closed state (waiting for a connection) + */ + CLOSED, + + /** + * Socket connection has been accepted. Waiting for web server to send CRY opcode + */ + WAIT_WEB_CRY, + + /** + * Waiting for web server to send SEL opcode + */ + WAIT_WEB_SEL, + + /** + * Retrying. Waiting for web server to send CRY opcode + */ + RETRY_WAIT_WEB_CRY, + + /** + * Retrying. Waiting for web server to send SEL opcode + */ + RETRY_WAIT_WEB_SEL, + + /** + * Exchange keys phase + */ + EXCHANGE_KEYS, + + /** + * Waiting for web server to send CAP opcode + */ + WAIT_WEB_CAP, + + /** + * Send CAP opcode to web server + */ + WAIT_CAP_ACK, + + /** + * Socket is up & running + */ + OPEN +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Ack.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Ack.java new file mode 100644 index 0000000000000000000000000000000000000000..e63457a773798c210be85688b632070de2cc9840 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Ack.java @@ -0,0 +1,60 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; + +/** + * ACK operation + */ +public class Ack implements IOperation { + @Override + public Opcode getOpcode() { + return Opcode.ACK; + } + + public Ack() { + } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + if (payload.length != 1) { + throw new IllegalArgumentException("ACK takes no data"); + } + + if (Opcode.fromOp(payload[0]) != getOpcode()) { + throw new IllegalArgumentException("Unmatched opcode"); + } + } + + @Override + public byte[] serialize() { + return new byte[]{getOpcode().opNbr}; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cap.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cap.java new file mode 100644 index 0000000000000000000000000000000000000000..a1bbca4ee959126429204207cba345e0897b4c85 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cap.java @@ -0,0 +1,55 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.cap.FeatCapability; +import me.peteras17.beacon.cap.ICapability; +import me.peteras17.beacon.socket.Opcode; + +/** + * CAP operation + */ +public class Cap extends CapabilityOp { + + /** + * Create CAP operation + */ + public Cap(ICapability capability) { + super(capability); + } + + @SuppressWarnings("unused") + public Cap() { + this(new FeatCapability()); + } + + @Override + public Opcode getOpcode() { + return Opcode.CAP; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/CapabilityOp.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/CapabilityOp.java new file mode 100644 index 0000000000000000000000000000000000000000..d7c0379c9d7a63dbea0ff1f18990a893913f8477 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/CapabilityOp.java @@ -0,0 +1,86 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.cap.FeatCapability; +import me.peteras17.beacon.cap.ICapability; +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; + +import java.util.Arrays; + +public abstract class CapabilityOp implements IOperation { + + /** + * Capability bitmap for this operation + */ + public final ICapability capability; + + /** + * Create a new capability operation with a capability instance + * + * @param capability Capability to copy + */ + public CapabilityOp(ICapability capability) { + this.capability = capability.copy(); + } + + /** + * Create an empty capability operation + */ + public CapabilityOp() { + this(new FeatCapability()); + } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + if (payload.length != (1 + FeatCapability.BITMAP_MAX_BYTES)) { + throw new IllegalArgumentException("Wrong amount of data for CRY operation"); + } + + if (Opcode.fromOp(payload[0]) != getOpcode()) { + throw new IllegalArgumentException("Unmatched opcode"); + } + + byte[] bitmap = Arrays.copyOfRange(payload, 1, payload.length); + capability.importPayload(bitmap); + } + + @Override + public byte[] serialize() { + byte[] payload = new byte[1 + FeatCapability.BITMAP_MAX_BYTES]; + payload[0] = getOpcode().opNbr; + + // Append bitmap bytes + byte[] msgBytes = this.capability.exportPayload(); + System.arraycopy(msgBytes, 0, payload, 1, msgBytes.length); + + // Return full payload + return payload; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cmd.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cmd.java new file mode 100644 index 0000000000000000000000000000000000000000..bd6c6d6df3e93b84285df370dc195df3494d707b --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cmd.java @@ -0,0 +1,63 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 04/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.Opcode; + +import java.nio.charset.StandardCharsets; + +/** + * CMD operation + */ +public class Cmd extends StringOp { + + /** + * Command requested to be executed + */ + public String command; + + public Opcode getOpcode() { + return Opcode.CMD; + } + + public Cmd() + { } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + super.buildFrom(payload); + command = new String(_payload); + } + + @Override + public byte[] serialize() { + // Return full payload + _payload = command.getBytes(StandardCharsets.UTF_8); + return super.serialize(); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cry.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cry.java new file mode 100644 index 0000000000000000000000000000000000000000..4f3d8959d380088e139461351e17feb8bc601090 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Cry.java @@ -0,0 +1,54 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.cap.CryptoCapability; +import me.peteras17.beacon.socket.Opcode; + +/** + * CRY operation + */ +public class Cry extends CapabilityOp { + + /** + * Create CRY operation + */ + public Cry(CryptoCapability capability) { + super(capability); + } + + @SuppressWarnings("unused") + public Cry() { + this(new CryptoCapability()); + } + + @Override + public Opcode getOpcode() { + return Opcode.CRY; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Inf.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Inf.java new file mode 100644 index 0000000000000000000000000000000000000000..10a958976479bbe3011b1dca8e5859a5b26990d1 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Inf.java @@ -0,0 +1,66 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import me.peteras17.beacon.BeaconCommon; +import me.peteras17.beacon.cap.ICapability; +import me.peteras17.beacon.metrics.IMetric; +import me.peteras17.beacon.metrics.MetricType; +import me.peteras17.beacon.socket.Opcode; + +import java.nio.charset.StandardCharsets; + +/** + * INF operation + */ +public class Inf extends StringOp { + + @Override + public Opcode getOpcode() { + return Opcode.INF; + } + + /** + * Create INF operation + */ + public Inf(BeaconCommon commonLib, ICapability capability) { + IMetric modMetric = commonLib.getMetricManager().getMetric(MetricType.MOD); + ObjectMapper mapper = new ObjectMapper(); + try { + ObjectNode root = mapper.createObjectNode(); + modMetric.serialize(root, capability); + _payload = mapper.writeValueAsString(root).getBytes(StandardCharsets.UTF_8); + } catch (JsonProcessingException | IllegalStateException ignored) { + throw new RuntimeException("Failed to serialize metrics payload"); + } + + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Key.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Key.java new file mode 100644 index 0000000000000000000000000000000000000000..283369b42ec3e8c2bf6cda33bf928657cba404ad --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Key.java @@ -0,0 +1,61 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import kotlin.NotImplementedError; +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; + +/** + * KEY operation + */ +public class Key implements IOperation { + + + @Override + public Opcode getOpcode() { + return Opcode.KEY; + } + + /** + * Create NOK operation object with no message + */ + public Key() { + throw new NotImplementedError(); + } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + throw new NotImplementedError(); + } + + @Override + public byte[] serialize() { + throw new NotImplementedError(); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Log.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Log.java new file mode 100644 index 0000000000000000000000000000000000000000..86591af60813c5579c6bcacead424f6f1ec966c8 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Log.java @@ -0,0 +1,50 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.Opcode; + +import java.nio.charset.StandardCharsets; + +/** + * LOG operation + */ +public class Log extends StringOp { + + @Override + public Opcode getOpcode() { + return Opcode.LOG; + } + + /** + * Create LOG operation + */ + public Log(String logLine) { + _payload = logLine.getBytes(StandardCharsets.UTF_8); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/ModMtr.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/ModMtr.java new file mode 100644 index 0000000000000000000000000000000000000000..048cf7e24b6e79589b3fbca4c6a0008d47f26eea --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/ModMtr.java @@ -0,0 +1,53 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.BeaconCommon; +import me.peteras17.beacon.cap.ICapability; +import me.peteras17.beacon.socket.Opcode; + +import java.nio.charset.StandardCharsets; + +/** + * MTR operation + */ +public class ModMtr extends StringOp { + + @Override + public Opcode getOpcode() { + return Opcode.MTR; + } + + /** + * Create MTR operation + */ + public ModMtr(BeaconCommon commonLib, ICapability capability) { + String metrics = commonLib.getMetricManager().getLastValues(capability); + _payload = metrics.getBytes(StandardCharsets.UTF_8); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Nok.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Nok.java new file mode 100644 index 0000000000000000000000000000000000000000..dac66924c4c2be3faddf53f864666b0c25109afc --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Nok.java @@ -0,0 +1,61 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.Opcode; + +import java.nio.charset.StandardCharsets; + +/** + * NOK operation + */ +public class Nok extends StringOp { + + + @Override + public Opcode getOpcode() { + return Opcode.NOK; + } + + /** + * Create NOK operation object with a message + * + * @param message Message for operation + */ + public Nok(String message) { + _payload = message.getBytes(StandardCharsets.UTF_8); + } + + /** + * Create NOK operation object with no message + */ + @SuppressWarnings("unused") + public Nok() { + this("No message provided"); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Nop.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Nop.java new file mode 100644 index 0000000000000000000000000000000000000000..96a79f6049990c22a2b5df4cbd5f75fedfe80dfe --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Nop.java @@ -0,0 +1,61 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; + +/** + * NOP operation + */ +public class Nop implements IOperation { + @Override + public Opcode getOpcode() { + return Opcode.NOP; + } + + @SuppressWarnings("unused") + public Nop() { + } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + if (payload.length != 1) { + throw new IllegalArgumentException("NOP takes no data"); + } + + if (Opcode.fromOp(payload[0]) != getOpcode()) { + throw new IllegalArgumentException("Unmatched opcode"); + } + } + + @Override + public byte[] serialize() { + return new byte[]{getOpcode().opNbr}; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Rty.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Rty.java new file mode 100644 index 0000000000000000000000000000000000000000..ad7a606d3731505e6e9d1b12b0e54d96d111ea85 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Rty.java @@ -0,0 +1,61 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; + +/** + * RTY operation + */ +public class Rty implements IOperation { + @Override + public Opcode getOpcode() { + return Opcode.RTY; + } + + @SuppressWarnings("unused") + public Rty() { + } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + if (payload.length != 1) { + throw new IllegalArgumentException("RTY takes no data"); + } + + if (Opcode.fromOp(payload[0]) != getOpcode()) { + throw new IllegalArgumentException("Unmatched opcode"); + } + } + + @Override + public byte[] serialize() { + return new byte[]{getOpcode().opNbr}; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Sel.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Sel.java new file mode 100644 index 0000000000000000000000000000000000000000..2cab9f5e18e7485220d05772ab45d9a1a16618e0 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/Sel.java @@ -0,0 +1,46 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 02/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.Opcode; + +/** + * SEL operation + */ +public class Sel extends CapabilityOp { + + @Override + public Opcode getOpcode() { + return Opcode.SEL; + } + + @SuppressWarnings("unused") + public Sel() { + super(); + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/StringOp.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/StringOp.java new file mode 100644 index 0000000000000000000000000000000000000000..f607cc8b55066113113d80bbf023d73087d9a11d --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/StringOp.java @@ -0,0 +1,74 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.IOperation; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +/** + * INF operation + */ +public abstract class StringOp implements IOperation { + + /** + * Byte array containing UTF-8-encoded metrics payload + */ + protected byte[] _payload = new byte[0]; + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + if(payload.length == 0) { + throw new IllegalArgumentException("CMD didn't get enough data"); + } + + byte[] cmdLengthBytes = Arrays.copyOfRange(payload, 1, 1 + Integer.BYTES); + int cmdLength = ByteBuffer.wrap(cmdLengthBytes).getInt(); + _payload = Arrays.copyOfRange(payload, 1 + Integer.BYTES, 1 + Integer.BYTES + cmdLength); + } + + @Override + public byte[] serialize() { + byte[] payload = new byte[1 + Integer.BYTES + _payload.length]; + byte[] lengthPayload = ByteBuffer.allocate(Integer.BYTES) + .order(ByteOrder.BIG_ENDIAN) + .putInt(_payload.length) + .array(); + + + // Append parts + payload[0] = getOpcode().opNbr; + System.arraycopy(lengthPayload, 0, payload, 1, lengthPayload.length); + System.arraycopy(_payload, 0, payload, 1 + lengthPayload.length, _payload.length); + + // Return full payload + return payload; + } +} diff --git a/mods/common/src/main/java/me/peteras17/beacon/socket/ops/WebMtr.java b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/WebMtr.java new file mode 100644 index 0000000000000000000000000000000000000000..6ac6446fe09b092cafa717e26711c49e15e52f94 --- /dev/null +++ b/mods/common/src/main/java/me/peteras17/beacon/socket/ops/WebMtr.java @@ -0,0 +1,58 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 01/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.socket.ops; + +import me.peteras17.beacon.socket.Opcode; + +/** + * MTR operation, from web server + */ +public class WebMtr extends StringOp { + + @Override + public Opcode getOpcode() { + return Opcode.MTR; + } + + + @SuppressWarnings("unused") + public WebMtr() { + _payload = new byte[0]; + } + + @Override + public void buildFrom(byte[] payload) throws IllegalArgumentException { + if (payload.length < 1) { + throw new IllegalArgumentException(); + } + + if (payload[0] != getOpcode().opNbr) { + throw new IllegalArgumentException(); + } + } +} diff --git a/mods/common/src/main/templates/ModVersion.java.in b/mods/common/src/main/templates/ModVersion.java.in new file mode 100644 index 0000000000000000000000000000000000000000..eb802e039235524e73be08f690cb31aa79e18c21 --- /dev/null +++ b/mods/common/src/main/templates/ModVersion.java.in @@ -0,0 +1,37 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 24/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon; + +public class ModVersion { + + /** + * Compiled mod's version + */ + public static final String VERSION = "${version}"; + +} diff --git a/mods/common/src/test/java/DummyTest.java b/mods/common/src/test/java/DummyTest.java deleted file mode 100644 index 770c4cbad7f10ee9f87de76658011296a5db9fd7..0000000000000000000000000000000000000000 --- a/mods/common/src/test/java/DummyTest.java +++ /dev/null @@ -1,11 +0,0 @@ -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class DummyTest -{ - @Test - public void testDummy() - { - Assertions.assertTrue(true); - } -} diff --git a/mods/common/src/test/java/generic/LifecycleTest.java b/mods/common/src/test/java/generic/LifecycleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3d1dd9bc43f9c0953ebc83cf058f44c51a6e3d9b --- /dev/null +++ b/mods/common/src/test/java/generic/LifecycleTest.java @@ -0,0 +1,164 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package generic;import me.peteras17.beacon.BeaconCommon; +import me.peteras17.beacon.BeaconStatus; +import me.peteras17.beacon.CommandManager; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import utils.Constants; + +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.atomic.AtomicReference; + +public class LifecycleTest { + private BeaconCommon commonLib; + + @BeforeEach + public void setup() + { + commonLib = new BeaconCommon(); + } + + @AfterEach + public void teardown() + { + // Try to stop the library so it frees ports + commonLib.beaconStop(); + } + + /** + * Tests nominal lifecycle: .beaconPreHeat(), .beaconStart(), .beaconStop() + * Tests /heartbeat endpoint + * Tests /beacon command execution + */ + @Test + public void testNominalLifecycle() { + + AtomicReference cmdMgr = new AtomicReference<>(); + + // Instantiate library, and start it + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(cmdMgr::set)); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + // Test Beacon command execution + Assertions.assertEquals(BeaconStatus.OK, cmdMgr.get().getRootCommand().execute(null).status()); + + // Check Beacon is responding to heartbeats + URLConnection conn = Assertions.assertDoesNotThrow(() -> { + URL heartbeatUrl = new URI(Constants.HEARTBEAT_URL).toURL(); + return heartbeatUrl.openConnection(); + }); + Assertions.assertDoesNotThrow(() -> (((HttpURLConnection)conn).getResponseCode())); + + // Stop Beacon + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + } + + /** + * Tests cases where calls to .beaconPreHeat() shouldn't work + */ + @Test + public void testNoPreHeat() + { + // Pre-heat, and try to call it again + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(commandManager -> {})); + Assertions.assertEquals(BeaconStatus.TOO_HOT, commonLib.beaconPreHeat(commandManager -> {})); + + // Start lib, and try to call .beaconPreHeat() again + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + Assertions.assertEquals(BeaconStatus.TOO_HOT, commonLib.beaconPreHeat(commandManager -> {})); + + // Stop lib, and try to call .beaconPreHeat() again (it only works once after instantiating the library) + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + Assertions.assertEquals(BeaconStatus.TOO_HOT, commonLib.beaconPreHeat(commandManager -> {})); + } + + /** + * Tests cases where calls to .beaconStart() shouldn't work + */ + @Test + public void testNoStart() + { + // Can't call .beaconStart() before call to .beaconPreHeat() + Assertions.assertEquals(BeaconStatus.TOO_COLD, commonLib.beaconStart("", cmd -> null)); + + // Pre-heat, start lib + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(commandManager -> {})); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + // Can't call .beaconStart() because it's already running + Assertions.assertEquals(BeaconStatus.ALREADY_STARTED, commonLib.beaconStart("", cmd -> null)); + } + + /** + * Tests cases where calls to .beaconStop() shouldn't work + */ + @Test + public void testNoStop() + { + // Can't call .beaconStop() if it's not running + Assertions.assertEquals(BeaconStatus.NOT_STARTED, commonLib.beaconStop()); + + // Pre-heat, try to stop + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(commandManager -> {})); + Assertions.assertEquals(BeaconStatus.NOT_STARTED, commonLib.beaconStop()); + + // Start library, and stop + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + + // Can't call .beaconStop() because it's stopped + Assertions.assertEquals(BeaconStatus.NOT_STARTED, commonLib.beaconStop()); + } + + /** + * Tests that Beacon's common library does not execute commands before a call to .beaconStart() + */ + @Test + public void testCommandBeforeStart() + { + AtomicReference cmdMgr = new AtomicReference<>(); + + // Instantiate library, and pre-heat it. Try to execute command + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(cmdMgr::set)); + Assertions.assertEquals(BeaconStatus.NOT_STARTED, cmdMgr.get().getRootCommand().execute(null).status()); + + // Start library, and retry + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + Assertions.assertEquals(BeaconStatus.OK, cmdMgr.get().getRootCommand().execute(null).status()); + + // Stop Beacon, and retry + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + Assertions.assertEquals(BeaconStatus.NOT_STARTED, cmdMgr.get().getRootCommand().execute(null).status()); + } +} diff --git a/mods/common/src/test/java/generic/UrlTest.java b/mods/common/src/test/java/generic/UrlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..074b1bc7953b37c9b55008eed374d9f65d476f97 --- /dev/null +++ b/mods/common/src/test/java/generic/UrlTest.java @@ -0,0 +1,278 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package generic;import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.javalin.http.HttpStatus; +import me.peteras17.beacon.BeaconCommon; +import me.peteras17.beacon.BeaconStatus; +import me.peteras17.beacon.CommandManager; +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.cap.FeatCapability; +import me.peteras17.beacon.cap.ICapability; +import me.peteras17.beacon.metrics.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import utils.Constants; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Random; +import java.util.concurrent.atomic.AtomicReference; + +public class UrlTest { + private BeaconCommon commonLib; + + @BeforeEach + public void setup() + { + commonLib = new BeaconCommon(); + } + + @AfterEach + public void teardown() + { + // Try to stop the library so it frees ports + commonLib.beaconStop(); + } + + /** + * Tests /heartbeat URL while Beacon common library is not running + */ + @Test + public void testJavalinWhileNotRunning() + { + AtomicReference cmdMgr = new AtomicReference<>(); + + // Check Beacon does not respond to heartbeats before call to .beaconPreHeat() + Assertions.assertThrows(ConnectException.class, () -> { + URL heartbeatUrl = new URI(Constants.HEARTBEAT_URL).toURL(); + int ignored = ((HttpURLConnection) heartbeatUrl.openConnection()).getResponseCode(); + }); + + // Pre-heat library, and test again + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(cmdMgr::set)); + Assertions.assertThrows(ConnectException.class, () -> { + URL heartbeatUrl = new URI(Constants.HEARTBEAT_URL).toURL(); + int ignored = ((HttpURLConnection) heartbeatUrl.openConnection()).getResponseCode(); + }); + + // Start common lib. Request should work now + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + Assertions.assertDoesNotThrow(() -> { + URL heartbeatUrl = new URI(Constants.HEARTBEAT_URL).toURL(); + int ignored = ((HttpURLConnection) heartbeatUrl.openConnection()).getResponseCode(); + }); + + // Stop Beacon and test again + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + Assertions.assertThrows(ConnectException.class, () -> { + URL heartbeatUrl = new URI(Constants.HEARTBEAT_URL).toURL(); + int ignored = ((HttpURLConnection) heartbeatUrl.openConnection()).getResponseCode(); + }); + } + + /** + * Test nominal case where /heartbeat works + */ + @Test + public void testNominalHeartbeat() + { + AtomicReference cmdMgr = new AtomicReference<>(); + + // Instantiate library, and start it + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(cmdMgr::set)); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + // Check Beacon is responding to heartbeats + URLConnection conn = Assertions.assertDoesNotThrow(() -> { + URL heartbeatUrl = new URI(Constants.HEARTBEAT_URL).toURL(); + return heartbeatUrl.openConnection(); + }); + int httpStatus = Assertions.assertDoesNotThrow(() -> (((HttpURLConnection)conn).getResponseCode())); + Assertions.assertEquals(0, conn.getContentLength()); // No data returned in request + Assertions.assertEquals(HttpStatus.OK.getCode(), httpStatus); // No data returned in request + + // Stop Beacon + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + } + + /** + * Tests usage of /public when no public information metrics have been created + */ + @Test + public void testPublicWithoutMetric() + { + AtomicReference cmdMgr = new AtomicReference<>(); + + // Instantiate library, and start it + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat(cmdMgr::set)); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + // Check /public response + URLConnection conn = Assertions.assertDoesNotThrow(() -> { + URL heartbeatUrl = new URI(Constants.PUBLIC_URL).toURL(); + return heartbeatUrl.openConnection(); + }); + int httpStatus = Assertions.assertDoesNotThrow(() -> (((HttpURLConnection)conn).getResponseCode())); + Assertions.assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), httpStatus); + + // Stop Beacon + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + } + + /** + * Tests usage of /public when the public information metric's result cannot be serialized + */ + @Test + public void testPublicUnserializableMetric() + { + class UnserializableMetric implements IMetric { + + @Override + public MetricType getType() { + return MetricType.PROPERTIES; + } + + @Override + public String getName() { + return "Unserializable"; + } + + @Override + public Capability getNeededCapability() { + return Capability.ALWAYS_ACTIVE; + } + + @Override + public void serialize(ObjectNode on, ICapability capMgr) { + on.putPOJO("property", commonLib); // The library is too complex to serialize + } + + @Override + public IMetric findMetric(MetricType metricType) { + return metricType == getType() ? this : null; + } + } + + class MetricProvider implements IMetricProvider + { + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + rootGroup.addMetric(new UnserializableMetric()); + } + + @Override + public void stop() { + + } + } + + // Instantiate library, add metric and start it + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat((ignored) -> {})); + commonLib.getMetricManager() + .register(new MetricProvider()); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + // Check /public response + URLConnection conn = Assertions.assertDoesNotThrow(() -> { + URL heartbeatUrl = new URI(Constants.PUBLIC_URL).toURL(); + return heartbeatUrl.openConnection(); + }); + int httpStatus = Assertions.assertDoesNotThrow(() -> (((HttpURLConnection)conn).getResponseCode())); + Assertions.assertEquals(Integer.BYTES + 2, conn.getContentLength()); // Should return "{}" + String resp = Assertions.assertDoesNotThrow(() -> new BufferedReader(new InputStreamReader((InputStream) conn.getContent())).readLine()); + Assertions.assertEquals("\0\0\0\2{}", resp); + Assertions.assertEquals(HttpStatus.OK.getCode(), httpStatus); + + // Stop Beacon + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + } + + /** + * Test nominal usage of /public + */ + @Test + public void testNominalPublic() + { + int randomNumber = new Random().nextInt(); + + class MetricProvider implements IMetricProvider + { + public final MetricGroup publicGroup = new MetricGroup(MetricType.PROPERTIES, Capability.ALWAYS_ACTIVE); + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + publicGroup.addMetric(new MetricNode(MetricType.SERVER_UPTIME, Capability.ALWAYS_ACTIVE, () -> randomNumber)); + rootGroup.addMetric(publicGroup); + } + + @Override + public void stop() { } + } + + // Instantiate library, add metric and start it + MetricProvider provider = new MetricProvider(); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat((ignored) -> {})); + commonLib.getMetricManager() + .register(provider); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + // Get expected output + ICapability cap = new FeatCapability(); + cap.enable(Capability.DEFAULT_FEATURES); + ObjectMapper mapper = new ObjectMapper(); + ObjectNode root = mapper.createObjectNode(); + provider.publicGroup.serialize(root, cap); + String metricOutput = Assertions.assertDoesNotThrow(() -> mapper.writeValueAsString(root)); + String lengthStr = new String(ByteBuffer.allocate(Integer.BYTES) + .order(ByteOrder.BIG_ENDIAN) + .putInt(metricOutput.length()) + .array()); + + // Check /public response + URLConnection conn = Assertions.assertDoesNotThrow(() -> { + URL heartbeatUrl = new URI(Constants.PUBLIC_URL).toURL(); + return heartbeatUrl.openConnection(); + }); + int httpStatus = Assertions.assertDoesNotThrow(() -> (((HttpURLConnection)conn).getResponseCode())); + Assertions.assertEquals(Integer.BYTES + metricOutput.length(), conn.getContentLength()); + String resp = Assertions.assertDoesNotThrow(() -> new BufferedReader(new InputStreamReader((InputStream) conn.getContent())).readLine()); + Assertions.assertEquals(lengthStr + metricOutput, resp); + Assertions.assertEquals(HttpStatus.OK.getCode(), httpStatus); + + // Stop Beacon + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + } +} diff --git a/mods/common/src/test/java/me/peteras17/beacon/SocketManagerTest.java b/mods/common/src/test/java/me/peteras17/beacon/SocketManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..160eb3de1d9e1ee245074291b95516247f723dbc --- /dev/null +++ b/mods/common/src/test/java/me/peteras17/beacon/SocketManagerTest.java @@ -0,0 +1,440 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon; + +import me.peteras17.beacon.cap.*; +import me.peteras17.beacon.socket.IOperation; +import me.peteras17.beacon.socket.Opcode; +import me.peteras17.beacon.socket.SocketState; +import me.peteras17.beacon.socket.ops.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import utils.Constants; +import utils.SocketClient; + +import javax.websocket.*; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.AbstractMap; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + + +public class SocketManagerTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(SocketManagerTest.class); + + private static final ICapability featureCap = new FeatCapability(); + private static final CryptoCapability cryptoCap = new CryptoCapability(); + + private static final byte[][] DATA_CONNECTION_TEST = new byte[][] + { + new byte[] { }, // No data + new byte[] { '\12', '\34', '\56' }, // Random data + }; + + /** + * Array of operations needed for a handshake to be concluded correctly + * To be configured inside the test + */ + @SuppressWarnings("unchecked") + private final Map.Entry[] DATA_VALID_HANDSHAKE = new Map.Entry[]{ + new AbstractMap.SimpleEntry<>(new Cry(), Opcode.CRY), + new AbstractMap.SimpleEntry<>(new Sel(), Opcode.ACK), + new AbstractMap.SimpleEntry<>(new Cap(), Opcode.CAP), + new AbstractMap.SimpleEntry<>(new Ack(), Opcode.INF), + new AbstractMap.SimpleEntry<>(new WebMtr(), Opcode.MTR) + }; + + /** + * Array of operations needed for a handshake to be concluded with a retry + * To be configured inside the test + */ + @SuppressWarnings("unchecked") + private final Map.Entry[] DATA_RETRIED_HANDSHAKE = new Map.Entry[]{ + new AbstractMap.SimpleEntry<>(new Cry(), Opcode.CRY), + new AbstractMap.SimpleEntry<>(new Sel(), Opcode.RTY), + new AbstractMap.SimpleEntry<>(new Cry(), Opcode.CRY), + new AbstractMap.SimpleEntry<>(new Sel(), Opcode.ACK), + new AbstractMap.SimpleEntry<>(new Cap(), Opcode.CAP), + new AbstractMap.SimpleEntry<>(new Ack(), Opcode.INF), + new AbstractMap.SimpleEntry<>(new WebMtr(), Opcode.MTR) + }; + + /** + * Array of operations needed for a handshake to fail (after a retry) + * To be configured inside the test + */ + @SuppressWarnings("unchecked") + private final Map.Entry[] DATA_FAILED_HANDSHAKE = new Map.Entry[]{ + new AbstractMap.SimpleEntry<>(new Cry(), Opcode.CRY), + new AbstractMap.SimpleEntry<>(new Sel(), Opcode.RTY), + new AbstractMap.SimpleEntry<>(new Cry(), Opcode.CRY), + new AbstractMap.SimpleEntry<>(new Sel(), null) // No response when handshake fails + }; + + private static final BeaconCommon commonLib = new BeaconCommon(); + private static SocketManager libSocketManager; + + + @BeforeAll + public static void suiteSetup() throws NoSuchFieldException, IllegalAccessException { + // Instantiate library, and start it + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconPreHeat((mgr) -> {})); + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStart("", cmd -> null)); + + featureCap.enable(Capability.DEFAULT_FEATURES); + cryptoCap.enable(Capability.DEFAULT_CRYPTO_ALGOS); + + // Use reflection to retrieve socket manager instance + Field socketManagerField = commonLib.getClass().getDeclaredField("_socketMgr"); + socketManagerField.setAccessible(true); + libSocketManager = (SocketManager) socketManagerField.get(commonLib); + } + + @AfterAll + public static void suiteTeardown() { + // Stop Beacon + Assertions.assertEquals(BeaconStatus.OK, commonLib.beaconStop()); + } + + /** + * Test a nominal CryptoGen.LEGACY type of connection + * @implNote If any of the assertions inside the socket client's thread fail, test will run indefinitely (limitation) + */ + @Test + public void testNominalLegacyConnection() throws InterruptedException { + // Set legacy crypto gen - no crypto + cryptoCap.setCryptoGen(CryptoGen.LEGACY); + + // Disable logs + featureCap.disable(Capability.FEAT_LOGS); + + // Setup array of operations + ((Cry)DATA_VALID_HANDSHAKE[0].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Sel)DATA_VALID_HANDSHAKE[1].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Cap)DATA_VALID_HANDSHAKE[2].getKey()).capability.importPayload(featureCap.exportPayload()); + + AtomicInteger opIndex = new AtomicInteger(); + AtomicReference code = new AtomicReference<>(); + + // Check socket status + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + + Assertions.assertDoesNotThrow(() -> { + SocketClient client = new SocketClient(Constants.SOCKET_URL, session -> {}, (session, reason) -> code.set(reason.getCloseCode()), (c, payload) -> { + try { + // Check response opcode + if(payload[0] != DATA_VALID_HANDSHAKE[opIndex.get()].getValue().opNbr) + { + throw new AssertionError(); + } + + if(opIndex.incrementAndGet() >= DATA_VALID_HANDSHAKE.length) + { + Assertions.assertEquals(SocketState.OPEN, libSocketManager.getState()); + c.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Test done")); + return; + } + + // Send next message + c.sendMessage(DATA_VALID_HANDSHAKE[opIndex.get()].getKey().serialize()); + + } catch (Exception ignored) { + try { + c.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "Test done")); + } catch (IOException ignored1) {} + } + }); + Assertions.assertEquals(SocketState.WAIT_WEB_CRY, libSocketManager.getState()); + client.sendMessage(DATA_VALID_HANDSHAKE[opIndex.get()].getKey().serialize()); + client.waitClose(); + }); + + Assertions.assertEquals(CloseReason.CloseCodes.NORMAL_CLOSURE, code.get()); + + // Dirty, yes, but I don't see another way of waiting SocketManager to close the connection before checking the state + Thread.sleep(100); + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + } + + /** + * Test a nominal CryptoGen.LEGACY handshake, where first handshake attempt intentionally fails + * @implNote If any of the assertions inside the socket client's thread fail, test will run indefinitely (limitation) + */ + @Test + public void testRetriedLegacyConnection() throws InterruptedException { + // Set legacy crypto gen - no crypto + cryptoCap.setCryptoGen(CryptoGen.LEGACY); + + // Disable logs + featureCap.disable(Capability.FEAT_LOGS); + + // Setup array of operations + ((Cry)DATA_RETRIED_HANDSHAKE[0].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Sel)DATA_RETRIED_HANDSHAKE[1].getKey()).capability.importPayload(new CryptoCapability().exportPayload()); + ((Cry)DATA_RETRIED_HANDSHAKE[2].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Sel)DATA_RETRIED_HANDSHAKE[3].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Cap)DATA_RETRIED_HANDSHAKE[4].getKey()).capability.importPayload(featureCap.exportPayload()); + + AtomicInteger opIndex = new AtomicInteger(); + AtomicReference code = new AtomicReference<>(); + + // Check socket status + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + + Assertions.assertDoesNotThrow(() -> { + SocketClient client = new SocketClient(Constants.SOCKET_URL, session -> {}, (session, reason) -> code.set(reason.getCloseCode()), (c, payload) -> { + try { + // Check response opcode + if(payload[0] != DATA_RETRIED_HANDSHAKE[opIndex.get()].getValue().opNbr) + { + throw new AssertionError(); + } + + if(opIndex.incrementAndGet() >= DATA_RETRIED_HANDSHAKE.length) + { + Assertions.assertEquals(SocketState.OPEN, libSocketManager.getState()); + c.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Test done")); + return; + } + + // Index 2: retry handshake + if(2 == opIndex.get()) { + Assertions.assertEquals(SocketState.RETRY_WAIT_WEB_CRY, libSocketManager.getState()); + } + + // Send next message + c.sendMessage(DATA_RETRIED_HANDSHAKE[opIndex.get()].getKey().serialize()); + + } catch (Exception ignored) { + try { + c.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "Test done")); + } catch (IOException ignored1) {} + } + }); + Assertions.assertEquals(SocketState.WAIT_WEB_CRY, libSocketManager.getState()); + client.sendMessage(DATA_RETRIED_HANDSHAKE[opIndex.get()].getKey().serialize()); + client.waitClose(); + }); + + Assertions.assertEquals(CloseReason.CloseCodes.NORMAL_CLOSURE, code.get()); + + // Dirty, yes, but I don't see another way of waiting SocketManager to close the connection before checking the state + Thread.sleep(100); + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + } + + /** + * Tests that the socket manager closes the connection after a failed handshake + * @implNote If any of the assertions inside the socket client's thread fail, test will run indefinitely (limitation) + */ + @Test + public void testFailedLegacyConnection() throws InterruptedException { + // Set legacy crypto gen - no crypto + cryptoCap.setCryptoGen(CryptoGen.LEGACY); + + // Disable logs + featureCap.disable(Capability.FEAT_LOGS); + + // Setup array of operations + ((Cry)DATA_FAILED_HANDSHAKE[0].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Sel)DATA_FAILED_HANDSHAKE[1].getKey()).capability.importPayload(new CryptoCapability().exportPayload()); + ((Cry)DATA_FAILED_HANDSHAKE[2].getKey()).capability.importPayload(cryptoCap.exportPayload()); + ((Sel)DATA_FAILED_HANDSHAKE[3].getKey()).capability.importPayload(new CryptoCapability().exportPayload()); + + AtomicInteger opIndex = new AtomicInteger(); + AtomicReference code = new AtomicReference<>(); + + // Check socket status + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + + Assertions.assertDoesNotThrow(() -> { + SocketClient client = new SocketClient(Constants.SOCKET_URL, session -> {}, (session, reason) -> code.set(reason.getCloseCode()), (c, payload) -> { + try { + // Check response opcode + if(payload[0] != DATA_FAILED_HANDSHAKE[opIndex.get()].getValue().opNbr) + { + throw new AssertionError(); + } + + if(opIndex.incrementAndGet() >= DATA_FAILED_HANDSHAKE.length) + { + c.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Test done")); + return; + } + + // Send next message + c.sendMessage(DATA_FAILED_HANDSHAKE[opIndex.get()].getKey().serialize()); + + } catch (Exception ignored) { + try { + c.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "Test done")); + } catch (IOException ignored1) {} + } + }); + client.sendMessage(DATA_FAILED_HANDSHAKE[opIndex.get()].getKey().serialize()); + client.waitClose(); + }); + + // Returned when the handshake fails + Assertions.assertEquals(CloseReason.CloseCodes.UNEXPECTED_CONDITION, code.get()); + + // Dirty, yes, but I don't see another way of waiting SocketManager to close the connection before checking the state + Thread.sleep(100); + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + } + + + /** + * Tests that socket manager closes the connection after an unexpected, initial message + */ + @Test + public void testSocketConnection() + { + // All payloads should result in the websocket's connection being closed by the mod + for(byte[] payload : DATA_CONNECTION_TEST) + { + AtomicReference code = new AtomicReference<>(); + + Assertions.assertDoesNotThrow(() -> { + SocketClient client = new SocketClient(Constants.SOCKET_URL, session -> {}, (session, reason) -> code.set(reason.getCloseCode()), (ignoredC, ignoredS) -> {}); + client.sendMessage(payload); + client.waitClose(); + }); + + Assertions.assertEquals(CloseReason.CloseCodes.PROTOCOL_ERROR, code.get()); + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + } + } + + /** + * Tests that the socket manager only accepts one connection before the handshake is complete + */ + @Test + public void testMultipleConnectionsPreHandshake() throws DeploymentException, IOException, URISyntaxException, InterruptedException { + int assertTimeoutMs = 5000; + int connectRandMinBoundMs = 100; + int connectRandMaxBoundMs = 2000; + int clientCount = 25; + Random rand = new Random(); + CountDownLatch clientsClosed = new CountDownLatch(clientCount - 1); + CountDownLatch clientsAccepted = new CountDownLatch(1); + AtomicReference firstClient = new AtomicReference<>(); + AtomicBoolean prematureClose = new AtomicBoolean(false); + + // Check initial state + Assertions.assertEquals(SocketState.CLOSED, libSocketManager.getState()); + + Semaphore barrier = new Semaphore(0); + for(int i = 0; i < clientCount; i++) { + final int clientNum = i; + + // We need an additional latch... + // This one makes the callback for the session closed wait for the thread to come wake up and try to send a CRY + CountDownLatch connectionDroppedCounter = new CountDownLatch(1); + + SocketClient client = new SocketClient(Constants.SOCKET_URL, session -> { + LOGGER.info(() -> "Client " + clientNum + " connected with session " + session.getId()); + + new Thread(() -> { + try { + CryptoCapability capability = new CryptoCapability(); + capability.setCryptoGen(CryptoGen.LEGACY); + + // Simulate random order of connection + Thread.sleep(rand.nextInt(connectRandMinBoundMs, connectRandMaxBoundMs)); + + // For the threads that wake up before SocketManager is able to reject them, try to send a CRY + session.getBasicRemote().sendBinary(ByteBuffer.wrap(new Cry(capability).serialize())); + + // First accepted connection. Set atomic to true, and wait for all other clients to disconnect + if(session.isOpen()) + { + LOGGER.info(() -> "Client " + clientNum + " was accepted"); + Assertions.assertNotEquals(SocketState.CLOSED, libSocketManager.getState()); + firstClient.set(session); + clientsAccepted.countDown(); + connectionDroppedCounter.countDown(); + } + else + { + LOGGER.info(() -> "Client " + clientNum + " was rejected"); + connectionDroppedCounter.countDown(); + } + } catch (IllegalStateException e) { + LOGGER.info(() -> "Connection from client " + clientNum + " was closed before sending CRY"); + connectionDroppedCounter.countDown(); + } catch (InterruptedException | IOException e) { + throw new RuntimeException(e); + } + }).start(); + }, (session, reason) -> { + try { + connectionDroppedCounter.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + clientsClosed.countDown(); + LOGGER.info(() -> "Client " + clientNum + " closed with reason " + reason); + }, + (ignoredC, ignoredS) -> { + }, + false); + + // Start only after barrier is lifted + client.start(barrier); + } + + // Lift barrier + LOGGER.info(() -> "Lifting barrier"); + Thread.currentThread().setPriority(Thread.MIN_PRIORITY); + barrier.release(clientCount); + clientsAccepted.await(); + + // Wait for all clients, except one, to have their sessions closed + LOGGER.info(() -> "Waiting for other clients to disconnect"); + Assertions.assertTrue(clientsClosed.await(assertTimeoutMs, TimeUnit.MILLISECONDS)); + Assertions.assertFalse(prematureClose.get()); + + // Check final state + firstClient.get().close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, "Bye, Felicia")); + } +} diff --git a/mods/common/src/test/java/me/peteras17/beacon/cap/CryptoCapabilityTest.java b/mods/common/src/test/java/me/peteras17/beacon/cap/CryptoCapabilityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fd7d7c1255202d494c85fd8bc7c82e0930f00466 --- /dev/null +++ b/mods/common/src/test/java/me/peteras17/beacon/cap/CryptoCapabilityTest.java @@ -0,0 +1,50 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CryptoCapabilityTest { + + /** + * Test cryptographic generation-related methods + */ + @Test + public void testCryptoGen() + { + CryptoCapability cap = new CryptoCapability(); + + Assertions.assertEquals(CryptoGen.LEGACY, cap.getCryptoGen()); + cap.setCryptoGen(CryptoGen.CURRENT); + Assertions.assertEquals(CryptoGen.CURRENT, cap.getCryptoGen()); + + Assertions.assertEquals(CryptoGen.CURRENT, CryptoGen.of(CryptoGen.CURRENT.ordinal())); + Assertions.assertNull(CryptoGen.of(Integer.MAX_VALUE)); // Unknown value + } +} diff --git a/mods/common/src/test/java/me/peteras17/beacon/cap/FeatCapabilityTest.java b/mods/common/src/test/java/me/peteras17/beacon/cap/FeatCapabilityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..01e9ca7f6d16d5af9dc4d0525bc8ecea07f0bbaa --- /dev/null +++ b/mods/common/src/test/java/me/peteras17/beacon/cap/FeatCapabilityTest.java @@ -0,0 +1,279 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.cap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.stream.IntStream; + +public class FeatCapabilityTest { + + /** + * Tests setting and unsetting bits + */ + @Test + public void testSetUnset() + { + int[] allBits = IntStream.range(0, FeatCapability.BITMAP_MAX_BITS - 1).toArray(); + FeatCapability cap = new FeatCapability(); + + // Assert all bits at an initial state + for(int i : allBits) + { + Assertions.assertFalse(cap.supports(i)); + } + + // Enable all capabilities and assert values + cap.enable(Capability.DEFAULT_FEATURES); + for(Capability c : Capability.DEFAULT_FEATURES) + { + Assertions.assertTrue(cap.supports(c)); + } + + // Check that other bits are not set + int[] others = IntStream.range(0, FeatCapability.BITMAP_MAX_BITS - 1).filter(e -> Arrays.stream(Capability.DEFAULT_FEATURES).noneMatch(c -> c.bitIndex == e)).toArray(); + for(int i : others) + { + Assertions.assertFalse(cap.supports(i)); + } + + // Disable all capabilities + for(Capability c : Capability.DEFAULT_FEATURES) + { + cap.disable(c); + } + + // Check all bits are unset + Assertions.assertEquals(0, cap.bitmap.bitCount()); + + // Check that double-setting does not unset + cap.enable(Capability.CRYPTO_EXCH_DH2048); + cap.enable(Capability.CRYPTO_EXCH_DH2048); + Assertions.assertTrue(cap.supports(Capability.CRYPTO_EXCH_DH2048)); + + // Check that double-unsetting does not set + cap.disable(Capability.CRYPTO_EXCH_DH2048); + cap.disable(Capability.CRYPTO_EXCH_DH2048); + Assertions.assertFalse(cap.supports(Capability.CRYPTO_EXCH_DH2048)); + + // Checking that setting both individually and in a list does not unset + cap.enable(Capability.CRYPTO_EXCH_DH2048); + cap.enable(new Capability[]{ Capability.CRYPTO_EXCH_DH2048 }); + Assertions.assertTrue(cap.supports(Capability.CRYPTO_EXCH_DH2048)); + } + + /** + * Test capabilities intersection (AND operation) + */ + @Test + public void testIntersection() + { + // Test non-overlapping capabilities + // Example: 0b1100 AND 0b0011 = 0b0000 + { + ICapability cap1 = new FeatCapability(); + ICapability cap2 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + // Sanity check + Assertions.assertTrue(cap1.equals(emptyCap)); + + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + cap2.enable(Capability.CRYPTO_EXCH_DH4096); + cap1.intersect(cap2); + Assertions.assertFalse(cap2.equals(emptyCap)); + Assertions.assertTrue(cap1.equals(emptyCap)); + } + + + // Test fully-overlapping capabilities + // Example: 0b0011 AND 0b0011 = 0b0011 + { + ICapability cap1 = new FeatCapability(); + ICapability cap2 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + cap2.enable(Capability.CRYPTO_EXCH_DH2048); + cap1.intersect(cap2); + Assertions.assertTrue(cap1.equals(cap2)); + Assertions.assertFalse(cap1.equals(emptyCap)); + } + + // Test partially-overlapping capabilities + // Example: 0b1110 AND 0b0111 = 0b0110 + { + ICapability cap1 = new FeatCapability(); + ICapability cap2 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + cap1.enable(Capability.CRYPTO_EXCH_RSA2048); + cap2.enable(Capability.CRYPTO_EXCH_DH2048); + cap2.enable(Capability.CRYPTO_SYMM_CHACHA20POLY1305); + cap1.intersect(cap2); + + Assertions.assertFalse(cap1.equals(cap2)); + Assertions.assertFalse(cap1.equals(emptyCap)); + Assertions.assertFalse(cap2.equals(emptyCap)); + + Assertions.assertTrue(cap1.supports(Capability.CRYPTO_EXCH_DH2048)); // Only overlap + Assertions.assertFalse(cap1.supports(Capability.CRYPTO_EXCH_RSA2048)); // Not overlapping + Assertions.assertFalse(cap1.supports(Capability.CRYPTO_SYMM_CHACHA20POLY1305)); // Not overlapping + } + + // Test subset capabilities, on A = A AND B, if A is a subset of B + // Example 0b0111 AND 0b0010 = 0b0010 + { + ICapability cap1 = new FeatCapability(); + ICapability cap2 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + cap2.enable(Capability.CRYPTO_EXCH_DH2048); + cap2.enable(Capability.CRYPTO_EXCH_RSA2048); + cap2.enable(Capability.CRYPTO_SYMM_CHACHA20POLY1305); + cap1.intersect(cap2); + + Assertions.assertFalse(cap1.equals(cap2)); + Assertions.assertFalse(cap1.equals(emptyCap)); + + Assertions.assertTrue(cap1.supports(Capability.CRYPTO_EXCH_DH2048)); // Only overlap + Assertions.assertFalse(cap1.supports(Capability.CRYPTO_EXCH_RSA2048)); // Not overlapping + Assertions.assertFalse(cap1.supports(Capability.CRYPTO_SYMM_CHACHA20POLY1305)); // Not overlapping + } + + // Test subset capabilities, on A = A AND B, if A is a subset of B + // Example 0b0111 AND 0b0010 = 0b0010 + { + ICapability cap1 = new FeatCapability(); + ICapability cap2 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + cap1.enable(Capability.CRYPTO_EXCH_RSA2048); + cap1.enable(Capability.CRYPTO_SYMM_CHACHA20POLY1305); + cap2.enable(Capability.CRYPTO_EXCH_DH2048); + cap1.intersect(cap2); + + Assertions.assertTrue(cap1.equals(cap2)); + Assertions.assertFalse(cap1.equals(emptyCap)); + + Assertions.assertTrue(cap1.supports(Capability.CRYPTO_EXCH_DH2048)); // Only overlap + Assertions.assertFalse(cap1.supports(Capability.CRYPTO_EXCH_RSA2048)); // Not overlapping + Assertions.assertFalse(cap1.supports(Capability.CRYPTO_SYMM_CHACHA20POLY1305)); // Not overlapping + } + } + + /** + * Tests .equals() method + */ + @Test + public void testEquality() + { + ICapability cap1 = new FeatCapability(); + ICapability cap2 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + // Sanity check - all should be equal at an initial state + Assertions.assertTrue(cap1.equals(cap2)); + Assertions.assertTrue(cap1.equals(emptyCap)); + + // Enable capability on first capability + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + Assertions.assertFalse(cap1.equals(emptyCap)); + Assertions.assertFalse(cap1.equals(cap2)); + + // Enable same capability on second capability + cap2.enable(Capability.CRYPTO_EXCH_DH2048); + Assertions.assertTrue(cap2.equals(cap1)); + Assertions.assertFalse(cap2.equals(emptyCap)); + + // Disable capability in both, and check again + cap1.disable(Capability.CRYPTO_EXCH_DH2048); + cap2.disable(Capability.CRYPTO_EXCH_DH2048); + Assertions.assertTrue(cap1.equals(emptyCap)); + Assertions.assertTrue(cap2.equals(emptyCap)); + } + + /** + * Test .import() and .export() + */ + @Test + public void testImportExport() + { + ICapability cap1 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + Assertions.assertArrayEquals(cap1.exportPayload(), emptyCap.exportPayload()); + cap1.enable(Capability.CRYPTO_EXCH_DH2048); + byte[] payload = cap1.exportPayload(); + Assertions.assertFalse(Arrays.equals(cap1.exportPayload(), emptyCap.exportPayload())); + + cap1.disable(Capability.CRYPTO_EXCH_DH2048); + Assertions.assertArrayEquals(cap1.exportPayload(), emptyCap.exportPayload()); + + cap1.importPayload(payload); + Assertions.assertFalse(Arrays.equals(cap1.exportPayload(), emptyCap.exportPayload())); + Assertions.assertArrayEquals(cap1.exportPayload(), payload); + } + + + /** + * Test that ALWAYS_ACTIVE capability is ignored + */ + @Test + public void testIgnoredValue() + { + ICapability cap1 = new FeatCapability(); + ICapability emptyCap = new FeatCapability(); + + Assertions.assertTrue(cap1.equals(emptyCap)); + + cap1.enable(Capability.ALWAYS_ACTIVE); + Assertions.assertTrue(cap1.equals(emptyCap)); + + cap1.disable(Capability.ALWAYS_ACTIVE); + Assertions.assertTrue(cap1.equals(emptyCap)); + } + + /** + * Test .copy() metbod + */ + @Test + public void testCopy() + { + FeatCapability cap1 = new FeatCapability(); + cap1.enable(Capability.CRYPTO_EXCH_ECDHP256); + + ICapability cap2 = cap1.copy(); + Assertions.assertTrue(cap1.equals(cap2)); + } +} diff --git a/mods/common/src/test/java/utils/Constants.java b/mods/common/src/test/java/utils/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..c29b6279a930a832c590ebbe07832cd1574056f7 --- /dev/null +++ b/mods/common/src/test/java/utils/Constants.java @@ -0,0 +1,37 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package utils; + +public class Constants { + public static final int JAVALIN_PORT = 25566; + public static final String JAVALIN_IP = "127.0.0.1"; + public static final String JAVALIN_URL = "http://" + JAVALIN_IP + ":" + JAVALIN_PORT; + public static final String HEARTBEAT_URL = JAVALIN_URL + "/heartbeat"; + public static final String PUBLIC_URL = JAVALIN_URL + "/public"; + public static final String SOCKET_URL = "ws://" + JAVALIN_IP + ":" + JAVALIN_PORT + "/socket"; +} diff --git a/mods/common/src/test/java/utils/SocketClient.java b/mods/common/src/test/java/utils/SocketClient.java new file mode 100644 index 0000000000000000000000000000000000000000..449c873d5db476b74cde882dc335a9129709d45e --- /dev/null +++ b/mods/common/src/test/java/utils/SocketClient.java @@ -0,0 +1,114 @@ +/* + * Beacon server-side mod source + * + * @author : @ + * @created : 05/09/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package utils; + +import javax.websocket.*; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +@SuppressWarnings("unused") +@ClientEndpoint +public class SocketClient { + private Session _session; + private final Consumer _onOpen; + private final BiConsumer _onClose; + private final BiConsumer _onMessage; + private final String _url; + private final CountDownLatch countDownLatch; + + public SocketClient(String url, Consumer onOpen, BiConsumer onClose, BiConsumer onMessage, boolean autoStart) throws URISyntaxException, DeploymentException, IOException { + _onOpen = onOpen; + _onClose = onClose; + _onMessage = onMessage; + _url = url; + countDownLatch = new CountDownLatch(1); + + if(autoStart) { + start(); + } + } + + public SocketClient(String url, Consumer onOpen, BiConsumer onClose, BiConsumer onMessage) throws URISyntaxException, DeploymentException, IOException { + this(Constants.SOCKET_URL, onOpen, onClose, onMessage, true); + } + + public void start() throws URISyntaxException, DeploymentException, IOException { + WebSocketContainer container = ContainerProvider.getWebSocketContainer(); + container.connectToServer(this, new URI(_url)); + } + + public void start(java.util.concurrent.Semaphore semaphore) { + new Thread(() -> { + try { + semaphore.acquire(); + start(); + } catch (InterruptedException | URISyntaxException | DeploymentException | IOException e) { + throw new RuntimeException(e); + } + }).start(); + } + + @OnOpen + public void onOpen(Session session) { + _session = session; + _onOpen.accept(session); + } + + @OnMessage + public void onMessage(String message) { + _onMessage.accept(this, java.util.Base64.getDecoder().decode(message.substring(1, message.length()-1))); + } + + @OnClose + public void onClose(Session session, CloseReason reason) { + _onClose.accept(session, reason); + countDownLatch.countDown(); + } + + public void close(CloseReason reason) throws IOException { + _session.close(reason); + } + + public void sendMessage(byte[] msg) throws Exception { + ByteBuffer buffer = ByteBuffer.wrap(msg); + _session.getBasicRemote().sendBinary(buffer); + } + + public void waitClose() throws InterruptedException { + countDownLatch.await(); + } + + public Session getSession() { + return _session; + } +} \ No newline at end of file diff --git a/mods/fabric/.idea/copyright/Beacon.xml b/mods/fabric/.idea/copyright/Beacon.xml new file mode 100644 index 0000000000000000000000000000000000000000..d540feab9dc176950613bdfdf8473d75c800e34e --- /dev/null +++ b/mods/fabric/.idea/copyright/Beacon.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/mods/fabric/.idea/copyright/profiles_settings.xml b/mods/fabric/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..f6661709748c320b294b7dcfa24c4014139ed92e --- /dev/null +++ b/mods/fabric/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/BeaconServer.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/BeaconServer.java new file mode 100644 index 0000000000000000000000000000000000000000..0d28cb218d4f9d956399e4336d5fa4bb59cc263d --- /dev/null +++ b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/BeaconServer.java @@ -0,0 +1,92 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 22/06/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.fabric; + +import com.mojang.brigadier.context.CommandContext; +import me.peteras17.beacon.BeaconCommon; +import me.peteras17.beacon.BeaconStatus; +import me.peteras17.beacon.cmd.ExecResult; +import me.peteras17.beacon.fabric.metrics.Server; +import me.peteras17.beacon.socket.ops.Cmd; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicReference; + +public class BeaconServer implements ModInitializer { + + public static final String MOD_ID = "beacon"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + private final AtomicReference srv = new AtomicReference<>(); + + @Override + public void onInitialize() { + LOGGER.info("Initializing Beacon"); + BeaconCommon common = new BeaconCommon(); + CommandCenter cmdCenter = new CommandCenter(); + + // Create all commands + common.getCmdManager() + .getRootCommand() + .appendSubcommand("about", (o) -> { + @SuppressWarnings("unchecked") CommandContext src = (CommandContext) o; + return new ExecResult(BeaconStatus.OK, "OK!"); + }); + + // Pre-heat common library + common.beaconPreHeat(cmdCenter); + + // Wait for server to be effectively up + ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> { + // Save instance, register metrics, and start Beacon's common library + srv.set(minecraftServer); + Server srvMetrics = new Server(srv.get()); + common.getMetricManager().register(srvMetrics); + common.beaconStart("", this::runCommand); + }); + + // Request Beacon's common library stop when the server stops + ServerLifecycleEvents.SERVER_STOPPING.register(server -> common.beaconStop()); + + // Request the command registry to call the command center's .register() function + CommandRegistrationCallback.EVENT.register(cmdCenter::register); + } + + @SuppressWarnings("UnusedReturnValue") + private ExecResult runCommand(Cmd operation) + { + srv.get().getCommandManager().executeWithPrefix(srv.get().getCommandSource(), operation.command); + LOGGER.debug("Executed command /{}", operation.command); + return new ExecResult(BeaconStatus.OK, "Executed"); + } +} diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/CommandCenter.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/CommandCenter.java index dcafe14bc5397fc7c60185d3e5a4b1959b8b8461..570a86d50ee64b8be1ab322649ea8ec654a7712e 100644 --- a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/CommandCenter.java +++ b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/CommandCenter.java @@ -1,3 +1,30 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 18/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.peteras17.beacon.fabric; import com.mojang.brigadier.CommandDispatcher; @@ -49,16 +76,6 @@ public class CommandCenter implements Consumer { - src.sendError(Text.of("Unknown Beacon command")); - return -1; - } - - case INVALID_DATA -> { - src.sendError(Text.of("Invalid data provided")); - return -1; - } - case OK -> { return 0; } diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/Main.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/Main.java deleted file mode 100644 index 9c48e076f0b2caa246897b4d37a37221a84bdc08..0000000000000000000000000000000000000000 --- a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/Main.java +++ /dev/null @@ -1,52 +0,0 @@ -package me.peteras17.beacon.fabric; - -import com.mojang.brigadier.context.CommandContext; -import me.peteras17.beacon.BeaconStatus; -import me.peteras17.beacon.cmd.ExecResult; -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.ServerCommandSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import me.peteras17.beacon.BeaconCommon; - -import java.util.concurrent.atomic.AtomicReference; - -public class Main implements ModInitializer { - - public static final String MOD_ID = "beacon"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - @Override - public void onInitialize() { - LOGGER.info("Initializing Beacon"); - BeaconCommon common = new BeaconCommon(); - CommandCenter cmdCenter = new CommandCenter(); - AtomicReference srv = new AtomicReference<>(); - - // Create all commands - common.getCmdManager() - .getRootCommand() - .appendSubcommand("about", (o) -> { - @SuppressWarnings("unchecked") CommandContext src = (CommandContext) o; - return new ExecResult(BeaconStatus.OK, "OK!"); - }); - - // Start Beacon's common library - common.beaconStart("", cmdCenter, () -> { - srv.get().getCommandManager().executeWithPrefix(srv.get().getCommandSource(), "beacon"); - }); - - // Wait for server to start to retrieve instance - ServerLifecycleEvents.SERVER_STARTED.register(srv::set); - - // Request Beacon's common library stop when the server stops - ServerLifecycleEvents.SERVER_STOPPING.register(server -> common.beaconStop()); - - // Request the command registry to call the command center's .register() function - CommandRegistrationCallback.EVENT.register(cmdCenter::register); - } - -} diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Players.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Players.java new file mode 100644 index 0000000000000000000000000000000000000000..5a3f479b1631e6f2aa4a6589deef9f001e75576a --- /dev/null +++ b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Players.java @@ -0,0 +1,120 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.fabric.metrics; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.*; +import net.minecraft.scoreboard.ScoreboardCriterion; +import net.minecraft.server.MinecraftServer; +import net.minecraft.stat.Stat; +import net.minecraft.stat.Stats; +import net.minecraft.world.level.LevelProperties; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +/** + * Metric provider for player information + * + * @implNote This class is not to be considered to be a true, root metric + * provider. Its usage must be confined to Server class, found in + * the same package + */ +class Players implements IMetricProvider { + + /** + * Name of the criteria that we can use to retrieve how much time a player has played on the server + */ + private static final String PLAYTIME_CRITERIA_NAME_PREFIX = "minecraft.custom:" + Stats.PLAY_TIME.getPath(); + + /** + * Minecraft server instance + */ + private final MinecraftServer _mcServer; + + /** + * Collection of metrics for each one of the players + */ + private final MetricCollection _metricCollection; + + private final ScoreboardCriterion _playtimeStat; + + /** + * Creates the instance for the players metrics provider + * + * @param mcServer Minecraft server instance + */ + public Players(MinecraftServer mcServer) { + _mcServer = mcServer; + _metricCollection = new MetricCollection(MetricType.PLAYERS, Capability.FEAT_PLAYERS_LIST, this::supply); + + Optional optionalStat = Stat.getOrCreateStatCriterion(PLAYTIME_CRITERIA_NAME_PREFIX); + if (optionalStat.isEmpty()) { + throw new IllegalStateException("Playtime stat not found in server!"); + } + _playtimeStat = optionalStat.get(); + } + + private List supply() { + List metricList = new LinkedList<>(); + float tickRate = _mcServer.getTickManager().getTickRate(); + + // Iterate through all the players, and create their metrics + _mcServer.getPlayerManager().getPlayerList().forEach(player -> { + MetricGroup playerMetrics = new MetricGroup(MetricType.PLAYERS, Capability.FEAT_PLAYERS_LIST, false); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_GUID, Capability.FEAT_PLAYERS_LIST, player.getUuid()::toString)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_USERNAME, Capability.FEAT_PLAYERS_LIST, player.getName()::getString)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_IS_OP, Capability.FEAT_PLAYERS_LIST, () -> player.getPermissionLevel() >= 3)); + playerMetrics.addMetric(new MetricNode(MetricType.WORLD_NAME, Capability.FEAT_PLAYERS_LIST, ((LevelProperties) player.getWorld().getLevelProperties())::getLevelName)); + //noinspection OptionalGetWithoutIsPresent + playerMetrics.addMetric(new MetricNode(MetricType.WORLD_TYPE, Capability.FEAT_PLAYERS_LIST, player.getWorld().getDimensionEntry().getKey().get().getValue()::toString)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_POS_X, Capability.FEAT_PLAYERS_LIST, () -> player.getPos().x)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_POS_Y, Capability.FEAT_PLAYERS_LIST, () -> player.getPos().y)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_POS_Z, Capability.FEAT_PLAYERS_LIST, () -> player.getPos().z)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_HEALTH, Capability.FEAT_PLAYERS_LIST, player::getHealth)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_HUNGER, Capability.FEAT_PLAYERS_LIST, player.getHungerManager()::getFoodLevel)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_SATURATION, Capability.FEAT_PLAYERS_LIST, player.getHungerManager()::getSaturationLevel)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_XP, Capability.FEAT_PLAYERS_LIST, () -> player.totalExperience)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_SESSION_PLAYTIME, Capability.FEAT_PLAYERS_LIST, () -> player.age / tickRate)); + playerMetrics.addMetric(new MetricNode(MetricType.PLAYER_TOTAL_PLAYTIME, Capability.FEAT_PLAYERS_LIST, () -> player.getStatHandler().getStat((Stat) _playtimeStat) / tickRate)); + metricList.add(playerMetrics); + }); + + return metricList; + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + rootGroup.addMetric(_metricCollection); + } + + @Override + public void stop() { + } +} diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Properties.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Properties.java new file mode 100644 index 0000000000000000000000000000000000000000..936d30f2ed9b5cbc9b740332ab19ae603da0da18 --- /dev/null +++ b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Properties.java @@ -0,0 +1,83 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.fabric.metrics; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.data.ServerType; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricNode; +import me.peteras17.beacon.metrics.MetricType; +import net.minecraft.server.MinecraftServer; + +import java.lang.management.ManagementFactory; + +/** + * Metric provider for server properties + * + * @implNote This class is not to be considered to be a true, root metric + * provider. Its usage must be confined to Server class, found in + * the same package + */ +public class Properties implements IMetricProvider { + + /** + * Minecraft server instance + */ + private final MinecraftServer _mcServer; + + /** + * Creates the instance for the server properties metrics provider + * + * @param mcServer Minecraft server instance + */ + public Properties(MinecraftServer mcServer) { + _mcServer = mcServer; + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + + MetricGroup _propertiesGroup = new MetricGroup(MetricType.PROPERTIES, Capability.ALWAYS_ACTIVE); + + // Create all metrics + _propertiesGroup.addMetric(new MetricNode(MetricType.SERVER_TYPE, Capability.ALWAYS_ACTIVE, () -> ServerType.FABRIC)); + _propertiesGroup.addMetric(new MetricNode(MetricType.SERVER_MINECRAFT_VERSION, Capability.ALWAYS_ACTIVE, _mcServer::getVersion)); + _propertiesGroup.addMetric(new MetricNode(MetricType.SERVER_PLAYER_COUNT, Capability.ALWAYS_ACTIVE, _mcServer::getCurrentPlayerCount)); + _propertiesGroup.addMetric(new MetricNode(MetricType.SERVER_MAX_PLAYER_COUNT, Capability.ALWAYS_ACTIVE, _mcServer::getMaxPlayerCount)); + _propertiesGroup.addMetric(new MetricNode(MetricType.SERVER_MOTD, Capability.ALWAYS_ACTIVE, _mcServer::getServerMotd)); + _propertiesGroup.addMetric(new MetricNode(MetricType.SERVER_UPTIME, Capability.ALWAYS_ACTIVE, () -> ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0f)); // Returns in milliseconds. Convert to seconds + + // Register group + rootGroup.addMetric(_propertiesGroup); + } + + @Override + public void stop() { + } +} diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Server.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Server.java new file mode 100644 index 0000000000000000000000000000000000000000..0646f2cc67c721bbbbb718ab424326544cb8d250 --- /dev/null +++ b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Server.java @@ -0,0 +1,76 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.fabric.metrics; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.metrics.IMetricProvider; +import me.peteras17.beacon.metrics.MetricGroup; +import me.peteras17.beacon.metrics.MetricType; +import net.minecraft.server.MinecraftServer; + +/** + * Provider for all server-related metrics + */ +public class Server implements IMetricProvider { + + /** + * Metric group for all server-related metrics + */ + private final MetricGroup _serverGroup; + + /** + * Minecraft server instance + */ + private final MinecraftServer _mcServer; + + /** + * Creates the instance for the server-related metrics provider + * + * @param mcServer Minecraft server instance + */ + public Server(MinecraftServer mcServer) { + _serverGroup = new MetricGroup(MetricType.SERVER, Capability.ALWAYS_ACTIVE); + _mcServer = mcServer; + } + + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + // Register subcategories + new Properties(_mcServer).register(_serverGroup); + new Players(_mcServer).register(_serverGroup); + new Worlds(_mcServer).register(_serverGroup); + + // Register group + rootGroup.addMetric(_serverGroup); + } + + @Override + public void stop() { + } +} diff --git a/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Worlds.java b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Worlds.java new file mode 100644 index 0000000000000000000000000000000000000000..9d9aba1385755551ff6e9f8fa18d71940d89a312 --- /dev/null +++ b/mods/fabric/src/main/java/me/peteras17/beacon/fabric/metrics/Worlds.java @@ -0,0 +1,164 @@ +/* + * Beacon server-side mod source + * + * @author : @PS-HEIG + * @created : 29/08/2025 + * + * Copyright (c) 2025 Pedro Alves da Silva, Nicolas Junod, Léo Rinsoz, Ilian Topalov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.peteras17.beacon.fabric.metrics; + +import me.peteras17.beacon.cap.Capability; +import me.peteras17.beacon.data.WorldWeather; +import me.peteras17.beacon.metrics.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.GameRules; +import net.minecraft.world.level.ServerWorldProperties; + +import java.util.*; + +/** + * Metric provider for world information + * + * @implNote This class is not to be considered to be a true, root metric + * provider. Its usage must be confined to Server class, found in + * the same package + */ +class Worlds implements IMetricProvider { + + /** + * Minecraft server instance + */ + private final MinecraftServer _mcServer; + + /** + * Collection of metrics for each one of the worlds + */ + private final MetricCollection _metricCollection; + + /** + * Creates the instance for the worlds metrics provider + * + * @param mcServer Minecraft server instance + */ + public Worlds(MinecraftServer mcServer) { + _mcServer = mcServer; + _metricCollection = new MetricCollection(MetricType.WORLDS, Capability.FEAT_WORLDS_LIST, this::supply); + } + + private WorldWeather getWeather(ServerWorld world) { + if (!world.isRaining()) { + return WorldWeather.CLEAR; + } else if (!world.isThundering()) { + return WorldWeather.RAINING; + } else { + return WorldWeather.THUNDERSTORM; + } + } + + private List supply() { + List metricList = new LinkedList<>(); + + // A world (level) is composed of 1...n dimensions, but the API naming is weird + // We need to find all dimensions of each world + + Map> worldDimensionsMap = new HashMap<>(); + + // Iterate through all the worlds, and create their metrics + _mcServer.getWorlds().forEach(w -> { + + final String worldName = ((ServerWorldProperties) w.getLevelProperties()).getLevelName(); + + // Create new key if we haven't found that world yet + if (!worldDimensionsMap.containsKey(worldName)) { + worldDimensionsMap.put(worldName, new ArrayList<>()); + } + + // Add dimension to map + worldDimensionsMap.get(worldName).add(w); + + }); + + // Now, iterate through all worlds and get their metrics, as well as their dimensions + for (Map.Entry> entry : worldDimensionsMap.entrySet()) { + + // First dimension will have same world information as other dimensions in the same world + ServerWorld firstDimension = entry.getValue().getFirst(); + + // Retrieve all game rules + HashMap gamerules = new HashMap<>(); + firstDimension.getGameRules().accept(new GameRules.Visitor() { + @Override + public > void visit(GameRules.Key key, GameRules.Type type) { + gamerules.put(key.getName(), firstDimension.getGameRules().get(key)); + } + + @Override + public void visitBoolean(GameRules.Key key, GameRules.Type type) { + gamerules.put(key.getName(), firstDimension.getGameRules().getBoolean(key)); + } + + @Override + public void visitInt(GameRules.Key key, GameRules.Type type) { + gamerules.put(key.getName(), firstDimension.getGameRules().getInt(key)); + } + }); + + // Iterate through all the dimensions + MetricCollection dimensionsMetrics = new MetricCollection(MetricType.DIMENSIONS, Capability.FEAT_WORLDS_LIST, () -> { + List metrics = new LinkedList<>(); + + for (ServerWorld dimension : entry.getValue()) { + metrics.add(new MetricNode(MetricType.WORLD_TYPE, Capability.FEAT_WORLDS_LIST, dimension.getDimensionEntry().getKey().get().getValue()::toString)); + } + + return metrics; + }); + + // Create world metric objects + MetricGroup worldMetrics = new MetricGroup(MetricType.WORLDS, Capability.FEAT_WORLDS_LIST, false); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_NAME, Capability.FEAT_WORLDS_LIST, entry::getKey)); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_TIME, Capability.FEAT_WORLDS_LIST, firstDimension::getTimeOfDay)); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_WEATHER, Capability.FEAT_WORLDS_LIST, () -> getWeather(firstDimension))); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_SPAWN_X, Capability.FEAT_WORLDS_LIST, firstDimension.getSpawnPos()::getX)); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_SPAWN_Y, Capability.FEAT_WORLDS_LIST, firstDimension.getSpawnPos()::getY)); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_SPAWN_Z, Capability.FEAT_WORLDS_LIST, firstDimension.getSpawnPos()::getZ)); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_DIFFICULTY, Capability.FEAT_WORLDS_LIST, ((ServerWorldProperties) firstDimension.getLevelProperties())::getDifficulty)); + worldMetrics.addMetric(new MetricNode(MetricType.WORLD_IS_HARDCORE, Capability.FEAT_WORLDS_LIST, ((ServerWorldProperties) firstDimension.getLevelProperties())::isHardcore)); + worldMetrics.addMetric(new MetricMap(MetricType.GAME_RULES, Capability.FEAT_WORLDS_LIST, () -> gamerules)); + worldMetrics.addMetric(dimensionsMetrics); + metricList.add(worldMetrics); + } + + return metricList; + } + + @Override + public void register(MetricGroup rootGroup) throws IllegalArgumentException { + rootGroup.addMetric(_metricCollection); + } + + @Override + public void stop() { + } +} diff --git a/mods/fabric/src/main/resources/fabric.mod.json b/mods/fabric/src/main/resources/fabric.mod.json index 42c3d1bcfd13e4fb92c73033ccfb8e4873965633..c1fe469b1d2c362113baeb81c63f974eaaff8d36 100644 --- a/mods/fabric/src/main/resources/fabric.mod.json +++ b/mods/fabric/src/main/resources/fabric.mod.json @@ -14,7 +14,7 @@ "me.peteras17.beacon.fabric.client.MainDataGenerator" ], "main": [ - "me.peteras17.beacon.fabric.Main" + "me.peteras17.beacon.fabric.BeaconServer" ] }, "mixins": [ diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..4faaeff74356052525d50cc156ea41fa8acac0ff --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,30 @@ +# Use official Python image as base +FROM python:3.11-slim + +# Environment variables +ARG BEACON_HOST="host.docker.internal" +ARG BEACON_PORT=25566 + +ENV BEACON_HOST=${BEACON_HOST} +ENV BEACON_PORT=${BEACON_PORT} + +# Set working directory +WORKDIR /app + +# Copy requirements first to leverage Docker cache +COPY ./web/requirements.txt . + +# Install dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of the application +COPY ./web . + +# Expose the port the app runs on +EXPOSE 5000 + +# Install gunicorn (recommended WSGI according to Flask documentation) +RUN pip install gunicorn + +# Command to run the application +CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"] \ No newline at end of file diff --git a/scripts/versioner.py b/scripts/versioner.py index f0c9f8dbdd90ec7b828e4cd4989b630828e80b30..2e50ef2a5f9151c6221efe2fd0feb753e69447f7 100644 --- a/scripts/versioner.py +++ b/scripts/versioner.py @@ -21,7 +21,8 @@ FILE_EXTENSIONS = [ ".py", # Python files ".gradle.kts", # Common lib Gradle project "gradle.properties", # Minecraft server-side properties - ".html" # Web pages + ".html", # Web pages + ".md" # READMEs ] # List of ignored directories @@ -42,6 +43,7 @@ VERSION_PATTERNS = [ "=\"{}\"", "=\'{}'", "Version {}", + "version/{}/", "mod_version={}" ] diff --git a/scripts/vm_setup.sh b/scripts/vm_setup.sh new file mode 100644 index 0000000000000000000000000000000000000000..07e837592a9f642ffa99388c217e3a3ef571f79e --- /dev/null +++ b/scripts/vm_setup.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Automatic Beacon landing page VM setup + +LANDING_FOLDER=/home/pdg/landing +LANDING_WWW_FOLDER="$LANDING_FOLDER/www" + +# Update all packages +apt update -y +apt upgrade -y + +# Install Lighttpd + SSL Python, Certbot, rsync, and htop +apt install -y lighttpd lighttpd-mod-openssl python3.11 certbot rsync htop + +# Setup folders +mkdir -p $LANDING_WWW_FOLDER + +# Obtain certificate +read -p "Enter this virtual machine's DNS: " HOST_DNS +certbot certonly --webroot -w /var/www/html/ -d $HOST_DNS +CERT_FOLDER="/etc/letsencrypt/live/$HOST_DNS" + +# Setup Lighttpd with SSL +cat > $LANDING_FOLDER/lighttpd.conf << EOL +# Setup server +server.name = "$HOST_DNS" +server.errorlog = "$LANDING_FOLDER/error.log" +server.document-root = "$LANDING_WWW_FOLDER" +server.port = 443 +server.username = "www-data" +server.groupname = "www-data" +server.modules += ( + "mod_openssl", + "mod_redirect" + ) + +# Associate .html with, well, HTML, and .css with CSS +mimetype.assign = ( + ".html" => "text/html", + ".css" => "text/css" + ) + +# Set index files +index-file.names = ( "index.html" ) + +# Set certificates for HTTPS +\$SERVER["socket"] == ":443" { + ssl.engine = "enable" + ssl.pemfile = "$CERT_FOLDER/fullchain.pem" + ssl.privkey = "$CERT_FOLDER/privkey.pem" +} + +# Redirect HTTP -> HTTPS +\$HTTP["scheme"] == "http" { + \$HTTP["host"] == "$HOST_DNS" { + url.redirect = ("/.*" => "https://$HOST_DNS\$0") + } +} +EOL + +# Create error file and chown it +touch "$LANDING_FOLDER/error.log" +chown www-data:www-data "$LANDING_FOLDER/error.log" + +# Move previous configuration and link to new one +mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.original +ln -s "$LANDING_FOLDER/lighttpd.conf" "/etc/lighttpd/lighttpd.conf" + +# Restart lighttpd +systemctl restart lighttpd \ No newline at end of file diff --git a/scripts/web_tests.py b/scripts/web_tests.py new file mode 100644 index 0000000000000000000000000000000000000000..7c5834251cc38637cc5a0fc404994cc7ed7f0b4b --- /dev/null +++ b/scripts/web_tests.py @@ -0,0 +1,139 @@ +import unittest +from unittest.mock import MagicMock, patch +from bitstring import BitArray +from routes.utils import SocketConnection, Opcode, ProtocolVersions, KeyExchangeProtocol, SymmetricProtocol, Capabilities +from config import Config + +class DummyServer: + ws = "ws://localhost:1234" +# end class + + +class TestCryptoBitmapTests(unittest.TestCase): + + def test_protocol_legacy_no_options(self): + Config.PROTOCOL_VERSION = ProtocolVersions.LEGACY + Config.KEY_EXCHANGE_PROTOCOLS = [] + Config.SYMMETRIC_PROTOCOLS = [] + + bitmap = Config.generate_crypto_bitmap() + self.assertEqual(bitmap.length, 128) + self.assertEqual(bitmap.uint, 0) + # end def + + def test_protocol_legacy_all_options(self): + Config.PROTOCOL_VERSION = ProtocolVersions.LEGACY + Config.KEY_EXCHANGE_PROTOCOLS = [KeyExchangeProtocol.RSA_2048, KeyExchangeProtocol.RSA_4096, KeyExchangeProtocol.DH_2048, KeyExchangeProtocol.DH_4096, KeyExchangeProtocol.ECDH_P256, KeyExchangeProtocol.ECDH_P384] + Config.SYMMETRIC_PROTOCOLS = [SymmetricProtocol.AES_128_GCM, SymmetricProtocol.AES_256_GCM, SymmetricProtocol.CHACHA20_POLY1305] + bitmap = Config.generate_crypto_bitmap() + self.assertEqual(bitmap.length, 128) + self.assertEqual(bitmap.uint, 0) # Legacy should still be all zeros + # end def + + def test_protocol_v1_partial_options(self): + Config.PROTOCOL_VERSION = ProtocolVersions.FIRST_VERSION + Config.KEY_EXCHANGE_PROTOCOLS = [KeyExchangeProtocol.ECDH_P256] + Config.SYMMETRIC_PROTOCOLS = [SymmetricProtocol.AES_128_GCM] + bitmap = Config.generate_crypto_bitmap() + + self.assertEqual(bitmap.length, 128) + self.assertEqual(bitmap[-2:].bin, '01') # Version 1 + self.assertEqual(int(bitmap[-3]), 0) # None not set + self.assertEqual(int(bitmap[-4]), 0) # RSA-2048 not set + self.assertEqual(int(bitmap[-5]), 0) # RSA-4096 not set + self.assertEqual(int(bitmap[-6]), 0) # DH-2048 not set + self.assertEqual(int(bitmap[-7]), 0) # DH-4096 not set + self.assertEqual(int(bitmap[-8]), 1) # ECDH-P256 set + self.assertEqual(int(bitmap[-9]), 0) # ECDH-P384 not set + self.assertEqual(int(bitmap[-35]), 1) # AES-128-GCM set + self.assertEqual(int(bitmap[-36]), 0) # AES-256-GCM not set + self.assertEqual(int(bitmap[-37]), 0) # ChaCha20-Poly1305 + # end def + + def test_protocol_v1_all_options(self): + Config.PROTOCOL_VERSION = ProtocolVersions.FIRST_VERSION + Config.KEY_EXCHANGE_PROTOCOLS = [KeyExchangeProtocol.NONE, KeyExchangeProtocol.RSA_2048, KeyExchangeProtocol.RSA_4096, KeyExchangeProtocol.DH_2048, KeyExchangeProtocol.DH_4096, KeyExchangeProtocol.ECDH_P256, KeyExchangeProtocol.ECDH_P384] + Config.SYMMETRIC_PROTOCOLS = [SymmetricProtocol.AES_128_GCM, SymmetricProtocol.AES_256_GCM, SymmetricProtocol.CHACHA20_POLY1305] + bitmap = Config.generate_crypto_bitmap() + + self.assertEqual(bitmap.length, 128) + bitmap = bitmap.bin + self.assertEqual(bitmap[-2:], '01') # Version 1 + self.assertEqual(bitmap[-3], '1') # None not set + self.assertEqual(bitmap[-4], '1') # RSA-2048 not set + self.assertEqual(bitmap[-5], '1') # RSA-4096 not set + self.assertEqual(bitmap[-6], '1') # DH-2048 not set + self.assertEqual(bitmap[-7], '1') # DH-4096 not set + self.assertEqual(bitmap[-8], '1') # ECDH-P256 set + self.assertEqual(bitmap[-9], '1') # ECDH-P384 not set + self.assertEqual(bitmap[-35], '1') # AES-128-GCM set + self.assertEqual(bitmap[-36], '1') # AES-256-GCM not set + self.assertEqual(bitmap[-37], '1') # ChaCha20-Poly1305 + # end def + + + def test_invalid_protocol_version(self): + Config.PROTOCOL_VERSION = 2 # Invalid version + + with self.assertRaises(ValueError): + Config.generate_crypto_bitmap() + # end with + # end def + +# end class + +class TestCapabilitiesBitmapTests(unittest.TestCase): + + def test_capabilities_one(self): + Config.CAPABILITIES = [Capabilities.OS] + + bitmap = Config.generate_capabilities_bitmap() + self.assertEqual(bitmap.length, 128) + bitmap = bitmap.bin + self.assertEqual(bitmap[-1], '1') # OS bit set + self.assertEqual(bitmap[-2], '0') # CPU_ARCH bit not set + self.assertEqual(bitmap[-3], '0') # JRE_VERSION bit snot et + self.assertEqual(bitmap[-4], '0') # JVM_CORES bit not set + self.assertEqual(bitmap[-5], '0') # CPU_USAGE bit not set + self.assertEqual(bitmap[-6], '0') # RAM_HEAP_MAX bit not set + self.assertEqual(bitmap[-7], '0') # RAM_HEAP_USAGE bit not set + self.assertEqual(bitmap[-8], '0') # RAM_NON_HEAP_MAX bit not set + self.assertEqual(bitmap[-9], '0') # RAM_NON_HEAP_USAGE bit not set + self.assertEqual(bitmap[-10], '0') # LAUNCH_ARGS bit not set + self.assertEqual(bitmap[-11], '0') # UPTIME bit not set + self.assertEqual(bitmap[-12], '0') # PLAYERS_LIST bit not set + self.assertEqual(bitmap[-13], '0') # WORLDS_LIST bit not set + self.assertEqual(bitmap[-14], '0') # LOGS bit not set + self.assertEqual(bitmap[-15], '0') # IO_WRITE_DELAY bit not set + self.assertEqual(bitmap[-16], '0') # IO_READ_DELAY bit not set + # end def + + def test_capabilities_all(self): + Config.CAPABILITIES = list(Capabilities) + + bitmap = Config.generate_capabilities_bitmap() + self.assertEqual(bitmap.length, 128) + bitmap = bitmap.bin + self.assertEqual(bitmap[-1], '1') # OS bit set + self.assertEqual(bitmap[-2], '1') # CPU_ARCH bit set + self.assertEqual(bitmap[-3], '1') # JRE_VERSION bit set + self.assertEqual(bitmap[-4], '1') # JVM_CORES bit set + self.assertEqual(bitmap[-5], '1') # CPU_USAGE bit set + self.assertEqual(bitmap[-6], '1') # RAM_HEAP_MAX bit set + self.assertEqual(bitmap[-7], '1') # RAM_HEAP_USAGE bit set + self.assertEqual(bitmap[-8], '1') # RAM_NON_HEAP_MAX bit set + self.assertEqual(bitmap[-9], '1') # RAM_NON_HEAP_USAGE bit set + self.assertEqual(bitmap[-10], '1') # LAUNCH_ARGS bit set + self.assertEqual(bitmap[-11], '1') # UPTIME bit set + self.assertEqual(bitmap[-12], '1') # PLAYERS_LIST bit set + self.assertEqual(bitmap[-13], '1') # WORLDS_LIST bit set + self.assertEqual(bitmap[-14], '1') # LOGS bit set + self.assertEqual(bitmap[-15], '1') # IO_WRITE_DELAY bit set + self.assertEqual(bitmap[-16], '1') # IO_READ_DELAY bit set + # end def + +# end class + +if __name__ == "__main__": + unittest.main() +# end if \ No newline at end of file diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index d09cadcf69e8abdf97f91b613d6533ab9a9fa9f7..0000000000000000000000000000000000000000 --- a/web/.gitignore +++ /dev/null @@ -1,283 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/pycharm,flask -# Edit at https://www.toptal.com/developers/gitignore?templates=pycharm,flask - -### Flask ### -instance/* -!instance/.gitignore -.webassets-cache -.env - -### Flask.Python Stack ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -### PyCharm ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### PyCharm Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -# https://plugins.jetbrains.com/plugin/7973-sonarlint -.idea/**/sonarlint/ - -# SonarQube Plugin -# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator-enh.xml -.idea/**/markdown-navigator/ - -# Cache file creation bug -# See https://youtrack.jetbrains.com/issue/JBR-2257 -.idea/$CACHE_FILE$ - -# CodeStream plugin -# https://plugins.jetbrains.com/plugin/12206-codestream -.idea/codestream.xml - -# Azure Toolkit for IntelliJ plugin -# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij -.idea/**/azureSettings.xml - -# End of https://www.toptal.com/developers/gitignore/api/pycharm,flask diff --git a/web/.idea/Beacon web.iml b/web/.idea/Beacon web.iml index 4a914832a46fd2768817f3b8856fda8f418a22a0..2c80e1269497d12e018fd6afa29982e56b0fb70d 100644 --- a/web/.idea/Beacon web.iml +++ b/web/.idea/Beacon web.iml @@ -1,21 +1,10 @@ - - - + - - - \ No newline at end of file diff --git a/web/.idea/misc.xml b/web/.idea/misc.xml index fa2cb8dd26d0f778d90162b09e50860df8901732..45cf7983f86bbaabdf169b6255b032740e18c190 100644 --- a/web/.idea/misc.xml +++ b/web/.idea/misc.xml @@ -3,4 +3,5 @@ + \ No newline at end of file diff --git a/web/config.py b/web/config.py index 3bf2a1a9dfa09f5b45a84de8eb2a8cb6438da6f9..9f0419e8355da35778648011d4d10f7164674109 100644 --- a/web/config.py +++ b/web/config.py @@ -1,3 +1,79 @@ from models.server import Server +from routes.utils import ProtocolVersions, KeyExchangeProtocol, SymmetricProtocol, Capabilities +from bitstring import BitArray +import logging +import os -MINECRAFT_SERVER = Server("http://localhost:25566", "Minecraft Server") +logging.basicConfig(level=logging.DEBUG) + +log = logging.getLogger(__name__) + +MINECRAFT_SERVER = Server( + os.getenv('BEACON_HOST', 'localhost'), + int(os.getenv('BEACON_PORT', '25566')), + "Minecraft Server", + "A Minecraft Server" +) + +log.info(f"Configured Minecraft server at {MINECRAFT_SERVER.ip}:{MINECRAFT_SERVER.port}") + +# Start the connection to the server immediately +MINECRAFT_SERVER.get_socket() + +class Config: + PROTOCOL_VERSION = ProtocolVersions.LEGACY + KEY_EXCHANGE_PROTOCOLS = [ + KeyExchangeProtocol.NONE, + ] + SYMMETRIC_PROTOCOLS = [] + CAPABILITIES = list(Capabilities) + CRYPTO_BITMAP = None + CAPABILITIES_BITMAP = None + + @classmethod + def get_crypto_bitmap(cls): + if cls.CRYPTO_BITMAP is None: + cls.CRYPTO_BITMAP = cls.generate_crypto_bitmap() + return cls.CRYPTO_BITMAP + # end def + + @classmethod + def generate_crypto_bitmap(cls): + bitmap = BitArray(128) + match (cls.PROTOCOL_VERSION): + case ProtocolVersions.LEGACY: + pass + case ProtocolVersions.FIRST_VERSION: + version = cls.PROTOCOL_VERSION.value + key_ex = sum(1 << protocol.value for protocol in cls.KEY_EXCHANGE_PROTOCOLS) + symmetric = sum(1 << protocol.value for protocol in cls.SYMMETRIC_PROTOCOLS) + + # Set version bits (127-126) + bitmap[-2:] = BitArray(uint=version, length=2) + + # Set key exchange bits (125-94) + bitmap[-34:-2] = BitArray(uint=key_ex, length=32) + + # Set symmetric bits (93-62) + bitmap[-66:-34] = BitArray(uint=symmetric, length=32) + case _: + raise ValueError("Unsupported protocol version") + return bitmap + # end def + + @classmethod + def get_capabilities_bitmap(cls): + if cls.CAPABILITIES_BITMAP is None: + cls.CAPABILITIES_BITMAP = cls.generate_capabilities_bitmap() + return cls.CAPABILITIES_BITMAP + # end def + + @classmethod + def generate_capabilities_bitmap(cls): + bitmap = BitArray(128) + for cap in cls.CAPABILITIES: + bitmap.set(1, 127 - cap.value) + return bitmap + # end def + +# end class \ No newline at end of file diff --git a/web/models/server.py b/web/models/server.py index 6f3b7258bc1fb9e792d3f5a5b3556f19ab810431..bc3e270f11326295679458ccc167a84b59a648e1 100644 --- a/web/models/server.py +++ b/web/models/server.py @@ -1,10 +1,31 @@ import requests +import logging +import json + +log = logging.getLogger(__name__) class Server: + NO_SOCKET_ERROR = "No socket connection" - def __init__(self, url: str, name: str): - self.url = url + def __init__(self, ip: str, port: int, name: str, description: str): + self.ip = ip + self.port = port + self.url = f"http://{self.ip}:{self.port}" + self.ws = f"ws://{self.ip}:{self.port}/socket" self.name = name + self.description = description + self.socket = None + # INFO + self.id = None + self.mod_version = None + ## JVM + self.jre_version = None + ## OS + self.os = None + + # Latest known data used for populating the dashboard template + self.metrics = {} + self.logs = [] # end def def check_status(self) -> bool: @@ -21,59 +42,92 @@ class Server: # end try # end def + def get_socket(self): + """ + Get or create an async socket connection. + Returns: + SocketConnection: The socket connection instance + """ + log.debug("Getting socket") + from routes.utils import SocketConnection + if self.socket is None: + self.socket = SocketConnection(self) + if not self.socket.connect(): + self.socket = None + # end if + return self.socket + # end def + + def close_socket(self): + """ + Close the socket connection if it exists + """ + if self.socket: + self.socket.close() + # end if + self.socket = None + # end def + def get_logs(self) -> tuple[list, str | None]: """ - Contact server to get logs. + Get the server logs via the socket connection. Returns: - list: The logs retrieved from the server. - str: An error message if the request fails. + dict: The server logs or an error message. """ - response = requests.get(f"{self.url}/logs") - if response.status_code == 200: - # decode bytes to string and split into lines - logs_str = response.content.decode("utf-8") - logs_list = logs_str.splitlines() - return logs_list, None + if self.socket is None: + self.get_socket() + return [], self.NO_SOCKET_ERROR + # end if + + log_response = self.socket.get_log_response() + if log_response: + logs = list(log_response) + logs = json.loads(json.dumps(logs)) + self.logs = logs + return self.logs, None else: - return [], "Failed to retrieve logs" + return [], "No log response" # end if # end def def get_metrics(self) -> tuple[dict, str | None]: """ - Contact server to get metrics. + Get the server metrics via the socket connection. Returns: - dict: The metrics retrieved from the server. - str: An error message if the request fails. + result: The server metrics. + error: An error message if applicable. """ - response = requests.get(f"{self.url}/metrics") - if response.status_code == 200: - return response.json(), None + if self.socket is None: + self.get_socket() + return {}, self.NO_SOCKET_ERROR + # end if + + metric_response = self.socket.get_metric_response() + if metric_response: + self.metrics = json.loads(metric_response) + return self.metrics, None else: - return {}, "Failed to retrieve metrics" + return {}, "No metric response" # end if # end def - def exec_command(self, command: str) -> tuple[str, str | None]: + def exec_command(self, command: str): """ - Execute a command on the server. + Execute a command on the server via the socket connection. Args: command (str): The command to execute. Returns: - str: The result of the command execution. - str: An error message if the request fails. + dict: The result of the command execution or an error message. """ - match command: - case "beacon": - response = requests.post(f"{self.url}/beacon") - case _: - return "", "Unknown command" - # end match + if self.socket is None: + self.get_socket() + return {"status": "error", "message": self.NO_SOCKET_ERROR} + # end if - if response.status_code == 200: - return response.text, None + if self.socket.send_command(command): + return {"status": "ok", "message": f"Command '{command}' sent"} else: - return "", "Failed to execute command" + return {"status": "error", "message": f"Failed to send command '{command}'"} # end if # end def diff --git a/web/requirements.txt b/web/requirements.txt index d78feabe2fd3b0b03cbc7b6b63d81320d415f817..5b6080bd11bb9e98bea4c16350acd0117edc416b 100644 --- a/web/requirements.txt +++ b/web/requirements.txt @@ -1,2 +1,5 @@ flask==3.1.1 -requests==2.32.5 \ No newline at end of file +flask[async]==3.1.1 +requests==2.32.5 +bitstring==4.3.1 +websocket-client==1.8.0 \ No newline at end of file diff --git a/web/routes/utils.py b/web/routes/utils.py index c9c993a00fb9383e347b016e957167368be40d02..3ecfd95d12c241cb63162c05b56ee1ee1124dd01 100644 --- a/web/routes/utils.py +++ b/web/routes/utils.py @@ -1,4 +1,13 @@ +import collections from models.server import Server +from enum import Enum +from bitstring import BitArray +import websocket +import threading +import logging +import base64 + +log = logging.getLogger(__name__) def get_server_status(server: Server): status = server.check_status() @@ -8,6 +17,7 @@ def get_server_status(server: Server): def get_server_logs(server: Server): logs, error = server.get_logs() if error: + log.error(f"Error getting logs: {error}") return {"status": "error", "error": error} # end if @@ -17,6 +27,7 @@ def get_server_logs(server: Server): def get_server_metrics(server: Server): data, error = server.get_metrics() if error: + log.error(f"Error getting metrics: {error}") return {"status": "error", "error": error} # end if @@ -30,4 +41,368 @@ def exec_server_command(server: Server, command: str): # end if return {"status": "ok", "result": result} -# end def \ No newline at end of file +# end def + +class ProtocolVersions(Enum): + LEGACY = 0b00 + FIRST_VERSION = 0b01 + +class KeyExchangeProtocol(Enum): + NONE = 0 + RSA_2048 = 1 + RSA_4096 = 2 + DH_2048 = 3 + DH_4096 = 4 + ECDH_P256 = 5 + ECDH_P384 = 6 + +class SymmetricProtocol(Enum): + AES_128_GCM = 0 + AES_256_GCM = 1 + CHACHA20_POLY1305 = 2 + +class Capabilities(Enum): + OS = 0 + CPU_ARCH = 1 + JRE_VERSION = 2 + JVM_CORES = 3 + CPU_USAGE = 4 + RAM_HEAP_MAX = 5 + RAM_HEAP_USAGE = 6 + RAM_NON_HEAP_MAX = 7 + RAM_NON_HEAP_USAGE = 8 + LAUNCH_ARGS = 9 + UPTIME = 10 + PLAYERS_LIST = 11 + WORLDS_LIST = 12 + LOGS = 13 + IO_WRITE_DELAY = 14 + IO_READ_DELAY = 15 + +class Opcode(Enum): + NOP = 0x00 # Unused (null byte) + ACK = 0x01 # Positive response + CRY = 0x10 # Crypto algorithm negotiation + SEL = 0x11 # Crypto algorithm selection + KEY = 0x12 # Key exchange + CAP = 0x13 # Capabilities negotiation + INF = 0x20 # Mod version info + MTR = 0x21 # Metrics request/response + LOG = 0x22 # Log upload + CMD = 0x23 # Command execution + RTY = 0xFE # Retry request + NOK = 0xFF # Negative response + +class SocketConnection: + MAX_RETRIES = 1 + + def __init__(self, server: Server): + self.server = server + self.socket = None + self.message_queue = [] + self.message_queue_lock = threading.Lock() + self.metrics_response = None + self.metric_lock = threading.Lock() + self.ask_metrics_thread = None + self.log_response = collections.deque(maxlen=50) + self.log_lock = threading.Lock() + self.message_event = threading.Event() + self.key_exchange_protocol = None + # end def + + def connect(self): + log.debug("Connecting socket") + try: + socket = websocket.WebSocketApp( + self.server.ws, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close, + on_open=self.on_open, + ) + self.ws_thread = threading.Thread(target=socket.run_forever) + self.ws_thread.daemon = True # Thread will close when main program exits + self.ws_thread.start() + + return True + except Exception as e: + log.warning(f"Socket connection error: {e}") + # end try + self.socket = None + return False + # end def + + def send(self, data: bytes): + log.debug(f"Sending data: {data}") + if self.socket: + try: + # Use correct method for binary data + self.socket.send(data, opcode=websocket.ABNF.OPCODE_BINARY) + log.debug("Sent") + except Exception as e: + log.warning(f"Socket send error: {e}") + # end try + # end if + # end def + + def receive(self) -> bytes: + log.debug("Receiving data") + if self.socket: + try: + self.message_event.wait(timeout=10.0) + self.message_event.clear() + with self.message_queue_lock: + if self.message_queue: + return self.message_queue.pop(0) + # end if + # end with + except Exception as e: + log.warning(f"Socket receive error: {e}") + return b"" + # end try + # end if + log.debug("No socket") + return b"" + # end def + + def close(self): + log.debug("Closing socket") + if self.socket: + self.socket.close() + self.socket = None + # end if + # end def + + def handshake(self): + from config import Config + if not self.perform_cry_handshake(Config.get_crypto_bitmap()): + self.server.close_socket() + return + # end if + + if self.key_exchange_protocol: + self.key_exchange() + # end if + + if not self.perform_cap_handshake(Config.get_capabilities_bitmap()): + self.server.close_socket() + return + # end if + + self.ask_metrics_thread = threading.Thread(target=self.ask_metrics) + self.ask_metrics_thread.daemon = True + self.ask_metrics_thread.start() + # end def + + def perform_cry_handshake(self, bitmap: BitArray) -> bool: + log.debug(f"Performing CRY handshake: {bitmap}") + retries = 0 + while retries <= self.MAX_RETRIES: + try: + # Send our bitmap + self.send(bytes([Opcode.CRY.value]) + bitmap.bytes) + # Receive their bitmap + response = self.receive() + if len(response) != 17 or response[0] != Opcode.CRY.value: + if retries == self.MAX_RETRIES: + self.send(bytes([Opcode.NOK.value])) + else: + self.send(bytes([Opcode.RTY.value])) + # end if + retries += 1 + continue + # end if + + their_bitmap = BitArray(bytes=response[1:]) + final_bitmap = bitmap & their_bitmap + + # Send AND'd bitmap + self.send(bytes([Opcode.SEL.value]) + final_bitmap.bytes) + + # Receive their AND'd bitmap + response = self.receive() + + if response[0] != Opcode.ACK.value: + if retries == self.MAX_RETRIES: + self.send(bytes([Opcode.NOK.value])) + else: + self.send(bytes([Opcode.RTY.value])) + # end if + retries += 1 + continue + # end if + + return True + except Exception as e: + log.warning(f"Handshake error: {e}") + retries += 1 + # end try + # end while + self.close() + return False + # end def + + def perform_cap_handshake(self, bitmap: BitArray) -> bool: + log.debug(f"Performing CAP handshake: {bitmap}") + try: + self.send(bytes([Opcode.CAP.value]) + bitmap.bytes) + + response = self.receive() + if response[0] != Opcode.CAP.value: + return False + # end if + + their_bitmap = BitArray(bytes=response[1:]) + final_bitmap = bitmap & their_bitmap + if final_bitmap.uint == 0: + self.send(bytes([Opcode.NOK.value])) + self.close() + return False + # end if + + self.send(bytes([Opcode.ACK.value])) + response = self.receive() + if response[0] != Opcode.INF.value: + self.close() + return False + # end if + + log.debug(response) + self.populate_server_info(self.get_length_prefixed_data(response[1:])) + + return True + except Exception as e: + log.warning(f"CAP handshake error: {e}") + self.close() + return False + # end try + # end def + + def key_exchange(self): + pass + # end def + + def encrypt(self): + pass + # end def + + def decrypt(self): + pass + # end def + + def on_message(self, wsapp, message): + decoded_message = base64.b64decode(message) + log.debug(f"Received WebSocket message [{Opcode(decoded_message[0])}]: {message}") + opcode = Opcode(decoded_message[0]) + if opcode == Opcode.MTR: + log.debug("Metrics response") + self.handle_metric_response(decoded_message[1:]) + elif opcode == Opcode.LOG: + log.debug("Log response") + self.handle_log_response(decoded_message[1:]) + else: + with self.message_queue_lock: + self.message_queue.append(decoded_message) + # end with + # end if + self.message_event.set() + # end def + + def populate_server_info(self, data: bytes): + log.debug(f"Populating server info: {data}") + # Populate server info from the data + import json + json_data = data.decode('utf-8') + server_info = json.loads(json_data).get("MOD") + self.server.id = server_info.get("MOD_SERVER_ID") + self.server.name = server_info.get("MOD_SERVER_NAME") + self.server.version = server_info.get("MOD_VERSION") + # end def + + def get_length_prefixed_data(self, data: str) -> bytes | None: + if len(data) < 4: + return None + # end if + + length = int.from_bytes(data[:4], 'big', signed=False) + if len(data) < length + 4: + return None + # end if + + return data[4:length+4] + # end def + + def handle_metric_response(self, metrics): + data = self.get_length_prefixed_data(metrics) + log.debug(f"Decoded metrics: {data}") + with self.metric_lock: + self.metrics_response = data.decode('utf-8') + # end with + # end def + + def get_metric_response(self): + with self.metric_lock: + metrics_response = self.metrics_response + # end with + return metrics_response + # end def + + def handle_log_response(self, logs): + data = self.get_length_prefixed_data(logs) + log.debug(f"Decoded log: {data}") + with self.log_lock: + self.log_response.append(data.decode('utf-8')) + # end with + # end def + + def get_log_response(self): + with self.log_lock: + log_response = self.log_response + # end with + return log_response + # end def + + def on_error(self, wsapp, error): + log.error(f"WebSocket error: {error}") + # end def + + def on_close(self, wsapp, close_status_code, close_msg): + log.debug(f"WebSocket closed : [{close_status_code}] {close_msg}") + self.server.close_socket() + # end def + + def on_open(self, wsapp): + log.debug("WebSocket opened") + self.socket = wsapp + threading.Thread(target=self.handshake).start() + # end def + + def ask_metrics(self) -> bool: + while self.socket is not None: + try: + self.send(bytes([Opcode.MTR.value])) + except Exception as e: + log.warning(f"Ask metrics error: {e}") + # end try + log.debug("Waiting before asking metrics again...") + threading.Event().wait(10.0) + # end while + # end def + + def send_command(self, command: str) -> bool: + try: + log.debug(f"Sending command: {command}") + cmd = command.encode('utf-8') + self.send(bytes([Opcode.CMD.value]) + len(cmd).to_bytes(4, 'big') + cmd) + response = base64.b64decode(str(self.receive())) + if response[0] == Opcode.ACK.value: + return True + # end if + except Exception as e: + log.warning(f"Send command error: {e}") + # end try + return False + # end def + + +# end class \ No newline at end of file diff --git a/web/routes/web.py b/web/routes/web.py index a1f355f1993cd3a4b171e848925fa353a2a21276..ecca22b241fa295b2eb9bdd1a091991af2d3225f 100644 --- a/web/routes/web.py +++ b/web/routes/web.py @@ -1,14 +1,16 @@ from flask import Blueprint, render_template -from config import MINECRAFT_SERVER +from config import MINECRAFT_SERVER, Config from routes.utils import * +import logging +log = logging.getLogger(__name__) web_bp = Blueprint("web", __name__) @web_bp.route("/") -def homepage(): - heartbeat = get_server_status(MINECRAFT_SERVER) - logs = get_server_logs(MINECRAFT_SERVER) - metrics = get_server_metrics(MINECRAFT_SERVER) +async def homepage(): + MINECRAFT_SERVER.get_socket() # start socket if not started + metrics = MINECRAFT_SERVER.get_metrics() + log.debug(f"Metrics: {metrics}") - return render_template("homepage.html", heartbeat=heartbeat, logs=logs, metrics=metrics) -# end def \ No newline at end of file + return render_template("homepage.html", server=MINECRAFT_SERVER, metrics=metrics, update_metrics="server/metrics") +# end def diff --git a/web/static/dashboard.css b/web/static/dashboard.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/web/static/font/Montserrat-Black.ttf b/web/static/font/Montserrat-Black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2fab7ab04f1be92aa334793fb80f6fa907a58bfa Binary files /dev/null and b/web/static/font/Montserrat-Black.ttf differ diff --git a/web/static/font/Montserrat-BlackItalic.ttf b/web/static/font/Montserrat-BlackItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..04d3b47f39e553037570fd27bd67533caf650f5b Binary files /dev/null and b/web/static/font/Montserrat-BlackItalic.ttf differ diff --git a/web/static/font/Montserrat-Bold.ttf b/web/static/font/Montserrat-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4033587556da7927c0a306d04bca9df4b2bea6fa Binary files /dev/null and b/web/static/font/Montserrat-Bold.ttf differ diff --git a/web/static/font/Montserrat-BoldItalic.ttf b/web/static/font/Montserrat-BoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0cc5c2cb6bd8ac533b89ea902fbf01bc09a5d395 Binary files /dev/null and b/web/static/font/Montserrat-BoldItalic.ttf differ diff --git a/web/static/font/Montserrat-ExtraBold.ttf b/web/static/font/Montserrat-ExtraBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..476ec30b6d18f02d4c124b38857885e3aece7701 Binary files /dev/null and b/web/static/font/Montserrat-ExtraBold.ttf differ diff --git a/web/static/font/Montserrat-ExtraBoldItalic.ttf b/web/static/font/Montserrat-ExtraBoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1ac9a9550451284db21fcb6e99c575b91e757bc Binary files /dev/null and b/web/static/font/Montserrat-ExtraBoldItalic.ttf differ diff --git a/web/static/font/Montserrat-ExtraLight.ttf b/web/static/font/Montserrat-ExtraLight.ttf new file mode 100644 index 0000000000000000000000000000000000000000..efaeab0672fea891c7e8b5ef69c23626d52c5160 Binary files /dev/null and b/web/static/font/Montserrat-ExtraLight.ttf differ diff --git a/web/static/font/Montserrat-ExtraLightItalic.ttf b/web/static/font/Montserrat-ExtraLightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a8d18decb135bab738e804a8ec58918f526dd7c7 Binary files /dev/null and b/web/static/font/Montserrat-ExtraLightItalic.ttf differ diff --git a/web/static/font/Montserrat-Italic.ttf b/web/static/font/Montserrat-Italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5f08df020422669282e44645de4d514ab3cbd68e Binary files /dev/null and b/web/static/font/Montserrat-Italic.ttf differ diff --git a/web/static/font/Montserrat-Light.ttf b/web/static/font/Montserrat-Light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..881f12d067d93c910479e042f454c613d62bcca8 Binary files /dev/null and b/web/static/font/Montserrat-Light.ttf differ diff --git a/web/static/font/Montserrat-LightItalic.ttf b/web/static/font/Montserrat-LightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b2991d025119e0641ac991b035158f989398a2db Binary files /dev/null and b/web/static/font/Montserrat-LightItalic.ttf differ diff --git a/web/static/font/Montserrat-Medium.ttf b/web/static/font/Montserrat-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c9a39ea1600c1c25dd3366bd03744839fc3eaca3 Binary files /dev/null and b/web/static/font/Montserrat-Medium.ttf differ diff --git a/web/static/font/Montserrat-MediumItalic.ttf b/web/static/font/Montserrat-MediumItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..086dd6e44fef0c0b10a76f52ab6ea587a3e545d2 Binary files /dev/null and b/web/static/font/Montserrat-MediumItalic.ttf differ diff --git a/web/static/font/Montserrat-Regular.ttf b/web/static/font/Montserrat-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..895e220a1799765801905b9d5837e89669a9939e Binary files /dev/null and b/web/static/font/Montserrat-Regular.ttf differ diff --git a/web/static/font/Montserrat-SemiBold.ttf b/web/static/font/Montserrat-SemiBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..161477a81e435a382c14d15644eb6ea3885ab4eb Binary files /dev/null and b/web/static/font/Montserrat-SemiBold.ttf differ diff --git a/web/static/font/Montserrat-SemiBoldItalic.ttf b/web/static/font/Montserrat-SemiBoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..73dc6c61e2aac9db839402e8f8a48064ee04a559 Binary files /dev/null and b/web/static/font/Montserrat-SemiBoldItalic.ttf differ diff --git a/web/static/font/Montserrat-Thin.ttf b/web/static/font/Montserrat-Thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c9cf1956535e402faf6ef540c55a36ad12a77e5b Binary files /dev/null and b/web/static/font/Montserrat-Thin.ttf differ diff --git a/web/static/font/Montserrat-ThinItalic.ttf b/web/static/font/Montserrat-ThinItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e6dfc05dcdc9949b0e0b0d00fd273a3ae66a4840 Binary files /dev/null and b/web/static/font/Montserrat-ThinItalic.ttf differ diff --git a/web/static/resources/fabric.png b/web/static/resources/fabric.png new file mode 100644 index 0000000000000000000000000000000000000000..bab3ad5d678860b4ad79ad9b88c4e97ee820aad0 Binary files /dev/null and b/web/static/resources/fabric.png differ diff --git a/web/static/resources/forge.png b/web/static/resources/forge.png new file mode 100644 index 0000000000000000000000000000000000000000..1585de149fc003b518eb5c7bf35404da0c6fd4bb Binary files /dev/null and b/web/static/resources/forge.png differ diff --git a/web/static/resources/vanilla.png b/web/static/resources/vanilla.png new file mode 100644 index 0000000000000000000000000000000000000000..7642332fbb6636f4c30ce9fd68cd695c874eda9e Binary files /dev/null and b/web/static/resources/vanilla.png differ diff --git a/web/static/style.css b/web/static/style.css new file mode 100644 index 0000000000000000000000000000000000000000..383152f65d0fdfa9aaaf6bf8ed718bc258f56cbd --- /dev/null +++ b/web/static/style.css @@ -0,0 +1,314 @@ +@font-face +{ + font-family: 'Montserrat'; + src: url('./font/Montserrat-Regular.ttf') format('truetype'); +} + +:root +{ + --icon_size: 42px; + --one_third: calc(100%/3); + --rounded_corners_graphs: 24px; + --app-font: "Montserrat", sans-serif; +} + +body +{ + background-color: #111; + color: white; + font-family: var(--app-font) !important; + overflow: hidden; +} + +body * +{ + font-family: var(--app-font) !important; +} + +h1 +{ + color: #555; + font-size: 50px; + text-transform: uppercase; + font-weight: regular; + line-height: 48px; + margin: 0px; +} + +h3 +{ + color: #aaa; +} + +h5 +{ + font-weight: regular; + margin-bottom: 20px; + padding: 0px; + text-transform: uppercase; +} + +p +{ + line-height: 24px; +} + +.center-text +{ + text-align: center; +} + +.data-column +{ + font-weight: bold; + height: auto; + padding-right: 10%; + text-align: right; + width: 50%; +} + +.label-data-columns +{ + display: flex; + flex-direction: row; + height: auto; + justify-content: center; +} + +.labels-column +{ + color: #666; + font-style: italic; + height: auto; + padding-left: 10%; + text-align: left; + width: 50%; +} +.metrics-pane +{ + display: flex; + flex-direction: column; + justify-content: space-around; +} +.metrics-pane > .gauge-container +{ + border-radius: inherit; + display: flex; + flex-direction: column; + justify-content: center; + width: inherit; +} +.metrics-pane > .gauge-container > * +{ + margin: 0px; + padding: 10px; +} +.metrics-pane > .gauge-container > progress +{ + margin-left: auto; + margin-right: auto; + height: 6px; + padding: 0px; + width: 85%; +} +.metrics-pane > .graphic-container +{ + border-radius: inherit; + display: flex; + flex-direction: column; + justify-content: center; + margin: 0px; + padding-left: 16px; + padding-right: 16px; +} +.metrics-pane > .graphic-container > #areaChart +{ + border-radius: 0px; +} + +.separator +{ + color: #ddd; + margin-bottom: 30px; +} + +.tabs +{ + overflow: hidden; +} +.tab button +{ + background-color: #333; + border: none; + border-bottom-left-radius: inherit; + border-bottom-right-radius: inherit; + border-top-left-radius: 6px; + border-top-right-radius: 6px; + color: white; + cursor: pointer; + font-weight: bold; + outline: none; + padding: 14px 16px; + transition: 0.3s; +} +.tab button:hover +{ + background-color: #ddd; + color: #222; +} +.tab button.active +{ + background-color: #22c6d1; +} + +.tabcontent +{ + border-top: none; + display: none; + padding: 6px 12px; +} + +#command-form +{ + border: none; + border-radius: 8px; + display: inline; + height: 26px; + outline: none; +} + +#command-input +{ + border: inherit; + border-radius: inherit; + height: inherit; + margin-bottom: 10px; + padding-left: 10px; + width: 92%; +} + +#command-send +{ + background-color: #444; + border: inherit; + border-radius: inherit; + color: white; + cursor: pointer; + display: inline; + font-weight: bold; + height: inherit; + margin-bottom: 10px; + margin-left: 4px; + transition: 0.3s; +} +#command-send:hover +{ + background-color: #ddd; + color: #222; +} +#command-send:active +{ + background-color: #22c6d1; +} + +#dashboard-main-section +{ + background-color: inherit; + display: grid; + grid-template-columns: var(--one_third) var(--one_third) var(--one_third); + grid-template-rows: 50% 50%; + left: 0px; + margin-left: 3vh; + margin-right: 3vh; + margin-top: 2vh; + overflow: hidden; + height: 100vh; + padding-right: var(--one_third); + width: 100%; +} +#dashboard-main-section > div +{ + background-color: #222; + border-radius: var(--rounded_corners_graphs); + margin-bottom: 1vh; + margin-right: 1vh; + text-align: center; +} +#dashboard-main-section > div:last-child +{ + grid-column: 4/1; +} + +#dashboard-page +{ + display: flex; + flex-direction: row; + overflow: hidden; +} + +#dashboard-right-pane +{ + background-color: #222; + border-radius: 36px; + display: flex; + flex-direction: column; + height: 100vh; + justify-content: center; + margin-right: 3vh; + margin-top: 2vh; + overflow: hidden; + position: absolute; + right: 0px; + width: var(--one_third); +} + +#description +{ + color: #ddd; + font-weight: lighter; +} + +#players +{ + display: block; +} + +#server-type-icon +{ + border-radius: 6px; + height: var(--icon_size); + max-height: var(--icon_size); + max-width: var(--icon_size); + margin-bottom: 0px; + margin-left: auto; + margin-right: auto; + margin-top: 0px; + width: var(--icon_size); +} + +#terminal-output +{ + background-color: black; + border: 1px solid #22c6d1; + border-radius: 12px; + color: white; + display: block; + font-family: "Courier New", monospace !important; + font-size: 14px; + height: 100%; + margin-left: auto; + margin-right: auto; + outline: none; + overflow: scroll; + padding-left: 10px; + resize: none; + width: 97%; +} + +#versions +{ + color: #aaa; + margin-top: 36px; + padding-left: 10%; + text-align: left !important; +} \ No newline at end of file diff --git a/web/static/uikit/css/uikit-rtl.min.css b/web/static/uikit/css/uikit-rtl.min.css new file mode 100644 index 0000000000000000000000000000000000000000..35189ed55fb1f4613a3dcdc1b28b6f4d898c88f5 --- /dev/null +++ b/web/static/uikit/css/uikit-rtl.min.css @@ -0,0 +1 @@ +/*! UIkit 3.23.12 | https://www.getuikit.com | (c) 2014 - 2025 YOOtheme | MIT License */html{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:16px;font-weight:400;line-height:1.5;-webkit-text-size-adjust:100%;background:#fff;color:#666}body{margin:0}.uk-link,a{color:#1e87f0;text-decoration:none;cursor:pointer}.uk-link-toggle:hover .uk-link,.uk-link:hover,a:hover{color:#0f6ecd;text-decoration:underline}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration-style:dotted}b,strong{font-weight:bolder}:not(pre)>code,:not(pre)>kbd,:not(pre)>samp{font-family:Consolas,monaco,monospace;font-size:.875rem;color:#f0506e;white-space:nowrap;padding:2px 6px;background:#f8f8f8}em{color:#f0506e}ins{background:#ffd;color:#666;text-decoration:none}mark{background:#ffd;color:#666}q{font-style:italic}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}audio,canvas,iframe,img,svg,video{vertical-align:middle}canvas,img,svg,video{max-width:100%;height:auto;box-sizing:border-box}img:not([src]){visibility:hidden;min-width:1px}iframe{border:0}address,dl,fieldset,figure,ol,p,pre,ul{margin:0 0 20px 0}*+address,*+dl,*+fieldset,*+figure,*+ol,*+p,*+pre,*+ul{margin-top:20px}.uk-h1,.uk-h2,.uk-h3,.uk-h4,.uk-h5,.uk-h6,.uk-heading-2xlarge,.uk-heading-3xlarge,.uk-heading-large,.uk-heading-medium,.uk-heading-small,.uk-heading-xlarge,h1,h2,h3,h4,h5,h6{margin:0 0 20px 0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-weight:400;color:#333;text-transform:none}*+.uk-h1,*+.uk-h2,*+.uk-h3,*+.uk-h4,*+.uk-h5,*+.uk-h6,*+.uk-heading-2xlarge,*+.uk-heading-3xlarge,*+.uk-heading-large,*+.uk-heading-medium,*+.uk-heading-small,*+.uk-heading-xlarge,*+h1,*+h2,*+h3,*+h4,*+h5,*+h6{margin-top:40px}.uk-h1,h1{font-size:2.23125rem;line-height:1.2}.uk-h2,h2{font-size:1.7rem;line-height:1.3}.uk-h3,h3{font-size:1.5rem;line-height:1.4}.uk-h4,h4{font-size:1.25rem;line-height:1.4}.uk-h5,h5{font-size:16px;line-height:1.4}.uk-h6,h6{font-size:.875rem;line-height:1.4}@media (min-width:960px){.uk-h1,h1{font-size:2.625rem}.uk-h2,h2{font-size:2rem}}ol,ul{padding-right:30px}ol>li>ol,ol>li>ul,ul>li>ol,ul>li>ul{margin:0}dt{font-weight:700}dd{margin-right:0}.uk-hr,hr{overflow:visible;text-align:inherit;margin:0 0 20px 0;border:0;border-top:1px solid #e5e5e5}*+.uk-hr,*+hr{margin-top:20px}address{font-style:normal}blockquote{margin:0 0 20px 0;font-size:1.25rem;line-height:1.5;font-style:italic;color:#333}*+blockquote{margin-top:20px}blockquote p:last-of-type{margin-bottom:0}blockquote footer{margin-top:10px;font-size:.875rem;line-height:1.5;color:#666}blockquote footer::before{content:"— "}pre{font:0.875rem/1.5 Consolas,monaco,monospace;color:#666;-moz-tab-size:4;tab-size:4;overflow:auto;padding:10px;border:1px solid #e5e5e5;border-radius:3px;background:#fff}pre code{font-family:Consolas,monaco,monospace}:focus{outline:0}:focus-visible{outline:2px dotted #333}::selection{background:#39f;color:#fff;text-shadow:none}details,main{display:block}summary{display:list-item}template{display:none}:root{--uk-breakpoint-s:640px;--uk-breakpoint-m:960px;--uk-breakpoint-l:1200px;--uk-breakpoint-xl:1600px}.uk-link-muted a,.uk-link-toggle .uk-link-muted,a.uk-link-muted{color:#999}.uk-link-muted a:hover,.uk-link-toggle:hover .uk-link-muted,a.uk-link-muted:hover{color:#666}.uk-link-text a,.uk-link-toggle .uk-link-text,a.uk-link-text{color:inherit}.uk-link-text a:hover,.uk-link-toggle:hover .uk-link-text,a.uk-link-text:hover{color:#999}.uk-link-heading a,.uk-link-toggle .uk-link-heading,a.uk-link-heading{color:inherit}.uk-link-heading a:hover,.uk-link-toggle:hover .uk-link-heading,a.uk-link-heading:hover{color:#1e87f0;text-decoration:none}.uk-link-reset a,a.uk-link-reset{color:inherit!important;text-decoration:none!important}.uk-link-toggle{color:inherit!important;text-decoration:none!important}.uk-heading-small{font-size:2.6rem;line-height:1.2}.uk-heading-medium{font-size:2.8875rem;line-height:1.1}.uk-heading-large{font-size:3.4rem;line-height:1.1}.uk-heading-xlarge{font-size:4rem;line-height:1}.uk-heading-2xlarge{font-size:6rem;line-height:1}.uk-heading-3xlarge{font-size:8rem;line-height:1}@media (min-width:960px){.uk-heading-small{font-size:3.25rem}.uk-heading-medium{font-size:3.5rem}.uk-heading-large{font-size:4rem}.uk-heading-xlarge{font-size:6rem}.uk-heading-2xlarge{font-size:8rem}.uk-heading-3xlarge{font-size:11rem}}@media (min-width:1200px){.uk-heading-medium{font-size:4rem}.uk-heading-large{font-size:6rem}.uk-heading-xlarge{font-size:8rem}.uk-heading-2xlarge{font-size:11rem}.uk-heading-3xlarge{font-size:15rem}}.uk-heading-divider{padding-bottom:calc(5px + .1em);border-bottom:calc(.2px + .05em) solid #e5e5e5}.uk-heading-bullet{position:relative}.uk-heading-bullet::before{content:"";display:inline-block;position:relative;top:calc(-.1 * 1em);vertical-align:middle;height:calc(4px + .7em);margin-left:calc(5px + .2em);border-right:calc(5px + .1em) solid #e5e5e5}.uk-heading-line{overflow:hidden}.uk-heading-line>*{display:inline-block;position:relative}.uk-heading-line>::after,.uk-heading-line>::before{content:"";position:absolute;top:calc(50% - (calc(.2px + .05em)/ 2));width:2000px;border-bottom:calc(.2px + .05em) solid #e5e5e5}.uk-heading-line>::before{left:100%;margin-left:calc(5px + .3em)}.uk-heading-line>::after{right:100%;margin-right:calc(5px + .3em)}[class*=uk-divider]{border:none;margin-bottom:20px}*+[class*=uk-divider]{margin-top:20px}.uk-divider-icon{position:relative;height:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22%23e5e5e5%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:50% 50%}.uk-divider-icon::after,.uk-divider-icon::before{content:"";position:absolute;top:50%;max-width:calc(50% - (50px / 2));border-bottom:1px solid #e5e5e5}.uk-divider-icon::before{left:calc(50% + (50px / 2));width:100%}.uk-divider-icon::after{right:calc(50% + (50px / 2));width:100%}.uk-divider-small{line-height:0}.uk-divider-small::after{content:"";display:inline-block;width:100px;max-width:100%;border-top:1px solid #e5e5e5;vertical-align:top}.uk-divider-vertical{width:max-content;height:100px;margin-right:auto;margin-left:auto;border-right:1px solid #e5e5e5}.uk-list{padding:0;list-style:none}.uk-list>*{break-inside:avoid-column}.uk-list>*>:last-child{margin-bottom:0}.uk-list>*>ul,.uk-list>:nth-child(n+2){margin-top:10px}.uk-list-circle,.uk-list-decimal,.uk-list-disc,.uk-list-hyphen,.uk-list-square{padding-right:30px}.uk-list-disc{list-style-type:disc}.uk-list-circle{list-style-type:circle}.uk-list-square{list-style-type:square}.uk-list-decimal{list-style-type:decimal}.uk-list-hyphen{list-style-type:'– '}.uk-list-muted>::marker{color:#999!important}.uk-list-emphasis>::marker{color:#333!important}.uk-list-primary>::marker{color:#1e87f0!important}.uk-list-secondary>::marker{color:#222!important}.uk-list-bullet>*{position:relative;padding-right:30px}.uk-list-bullet>::before{content:"";position:absolute;top:0;right:0;width:30px;height:1.5em;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-list-divider>:nth-child(n+2){margin-top:10px;padding-top:10px;border-top:1px solid #e5e5e5}.uk-list-striped>*{padding:10px 10px}.uk-list-striped>:nth-of-type(odd){border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.uk-list-striped>:nth-of-type(odd){background:#f8f8f8}.uk-list-striped>:nth-child(n+2){margin-top:0}.uk-list-large>*>ul,.uk-list-large>:nth-child(n+2){margin-top:20px}.uk-list-collapse>*>ul,.uk-list-collapse>:nth-child(n+2){margin-top:0}.uk-list-large.uk-list-divider>:nth-child(n+2){margin-top:20px;padding-top:20px}.uk-list-collapse.uk-list-divider>:nth-child(n+2){margin-top:0;padding-top:0}.uk-list-large.uk-list-striped>*{padding:20px 10px}.uk-list-collapse.uk-list-striped>*{padding-top:0;padding-bottom:0}.uk-list-collapse.uk-list-striped>:nth-child(n+2),.uk-list-large.uk-list-striped>:nth-child(n+2){margin-top:0}.uk-description-list>dt{color:#333;font-size:.875rem;font-weight:400;text-transform:uppercase}.uk-description-list>dt:nth-child(n+2){margin-top:20px}.uk-description-list-divider>dt:nth-child(n+2){margin-top:20px;padding-top:20px;border-top:1px solid #e5e5e5}.uk-table{border-collapse:collapse;border-spacing:0;width:100%;margin-bottom:20px}*+.uk-table{margin-top:20px}.uk-table th{padding:16px 12px;text-align:right;vertical-align:bottom;font-size:.875rem;font-weight:400;color:#999;text-transform:uppercase}.uk-table td{padding:16px 12px;vertical-align:top}.uk-table td>:last-child{margin-bottom:0}.uk-table tfoot{font-size:.875rem}.uk-table caption{font-size:.875rem;text-align:right;color:#999}.uk-table-middle,.uk-table-middle td{vertical-align:middle!important}.uk-table-divider>:first-child>tr:not(:first-child),.uk-table-divider>:not(:first-child)>tr,.uk-table-divider>tr:not(:first-child){border-top:1px solid #e5e5e5}.uk-table-striped tbody tr:nth-of-type(odd),.uk-table-striped>tr:nth-of-type(odd){background:#f8f8f8;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.uk-table-hover tbody tr:hover,.uk-table-hover>tr:hover{background:#ffd}.uk-table tbody tr.uk-active,.uk-table>tr.uk-active{background:#ffd}.uk-table-small td,.uk-table-small th{padding:10px 12px}.uk-table-large td,.uk-table-large th{padding:22px 12px}.uk-table-justify td:first-child,.uk-table-justify th:first-child{padding-right:0}.uk-table-justify td:last-child,.uk-table-justify th:last-child{padding-left:0}.uk-table-shrink{width:1px}.uk-table-expand{min-width:150px}.uk-table-link{padding:0!important}.uk-table-link>a{display:block;padding:16px 12px}.uk-table-small .uk-table-link>a{padding:10px 12px}@media (max-width:959px){.uk-table-responsive,.uk-table-responsive tbody,.uk-table-responsive td,.uk-table-responsive th,.uk-table-responsive tr{display:block}.uk-table-responsive thead{display:none}.uk-table-responsive td,.uk-table-responsive th{width:auto!important;max-width:none!important;min-width:0!important;overflow:visible!important;white-space:normal!important}.uk-table-responsive .uk-table-link:not(:first-child)>a,.uk-table-responsive td:not(:first-child):not(.uk-table-link),.uk-table-responsive th:not(:first-child):not(.uk-table-link){padding-top:5px!important}.uk-table-responsive .uk-table-link:not(:last-child)>a,.uk-table-responsive td:not(:last-child):not(.uk-table-link),.uk-table-responsive th:not(:last-child):not(.uk-table-link){padding-bottom:5px!important}.uk-table-justify.uk-table-responsive td,.uk-table-justify.uk-table-responsive th{padding-right:0;padding-left:0}}.uk-table tbody tr{transition:background-color .1s linear}.uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-table-striped>tr:nth-of-type(2n):last-child{border-bottom:1px solid #e5e5e5}.uk-icon{margin:0;border:none;border-radius:0;overflow:visible;font:inherit;color:inherit;text-transform:none;padding:0;background-color:transparent;display:inline-block;fill:currentcolor;line-height:0}button.uk-icon:not(:disabled){cursor:pointer}.uk-icon::-moz-focus-inner{border:0;padding:0}.uk-icon:not(.uk-preserve) [fill*="#"]:not(.uk-preserve){fill:currentcolor}.uk-icon:not(.uk-preserve) [stroke*="#"]:not(.uk-preserve){stroke:currentcolor}.uk-icon>*{transform:translate(0,0)}.uk-icon-image{width:20px;height:20px;background-position:50% 50%;background-repeat:no-repeat;background-size:contain;vertical-align:middle;object-fit:scale-down;max-width:none}.uk-icon-link{color:#999;text-decoration:none!important}.uk-icon-link:hover{color:#666}.uk-active>.uk-icon-link,.uk-icon-link:active{color:#595959}.uk-icon-button{box-sizing:border-box;width:36px;height:36px;border-radius:500px;background:#f8f8f8;color:#999;vertical-align:middle;display:inline-flex;justify-content:center;align-items:center;transition:.1s ease-in-out;transition-property:color,background-color}.uk-icon-button:hover{background-color:#ebebeb;color:#666}.uk-active>.uk-icon-button,.uk-icon-button:active{background-color:#dfdfdf;color:#666}.uk-range{-webkit-appearance:none;box-sizing:border-box;margin:0;vertical-align:middle;max-width:100%;width:100%;background:0 0}.uk-range:focus{outline:0}.uk-range::-moz-focus-outer{border:none}.uk-range:not(:disabled)::-webkit-slider-thumb{cursor:pointer}.uk-range:not(:disabled)::-moz-range-thumb{cursor:pointer}.uk-range::-webkit-slider-runnable-track{height:3px;background:#ebebeb;border-radius:500px}.uk-range:active::-webkit-slider-runnable-track,.uk-range:focus::-webkit-slider-runnable-track{background:#dedede}.uk-range::-moz-range-track{height:3px;background:#ebebeb;border-radius:500px}.uk-range:focus::-moz-range-track{background:#dedede}.uk-range::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-7px;height:15px;width:15px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-range::-moz-range-thumb{border:none;height:15px;width:15px;margin-top:-7px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-checkbox,.uk-input,.uk-radio,.uk-select,.uk-textarea{box-sizing:border-box;margin:0;border-radius:0;font:inherit}.uk-input{overflow:visible}.uk-select{text-transform:none}.uk-select optgroup{font:inherit;font-weight:700}.uk-textarea{overflow:auto}.uk-input[type=search]::-webkit-search-cancel-button,.uk-input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.uk-input[type=number]::-webkit-inner-spin-button,.uk-input[type=number]::-webkit-outer-spin-button{height:auto}.uk-input[type=date]::-webkit-datetime-edit,.uk-input[type=datetime-local]::-webkit-datetime-edit,.uk-input[type=time]::-webkit-datetime-edit{display:inline-flex;align-items:center;height:100%;padding:0}.uk-input::-moz-placeholder,.uk-textarea::-moz-placeholder{opacity:1}.uk-checkbox:not(:disabled),.uk-radio:not(:disabled){cursor:pointer}.uk-fieldset{border:none;margin:0;padding:0;min-width:0}.uk-input,.uk-textarea{-webkit-appearance:none}.uk-input,.uk-select,.uk-textarea{max-width:100%;width:100%;border:0 none;padding:0 10px;background:#fff;color:#666;border:1px solid #e5e5e5;transition:.2s ease-in-out;transition-property:color,background-color,border}.uk-input,.uk-select:not([multiple]):not([size]){height:40px;vertical-align:middle;display:inline-block}.uk-input:not(input),.uk-select:not(select){line-height:38px}.uk-select[multiple],.uk-select[size],.uk-textarea{padding-top:6px;padding-bottom:6px;vertical-align:top}.uk-select[multiple],.uk-select[size]{resize:vertical}.uk-input:focus,.uk-select:focus,.uk-textarea:focus{outline:0;background-color:#fff;color:#666;border-color:#1e87f0}.uk-input:disabled,.uk-select:disabled,.uk-textarea:disabled{background-color:#f8f8f8;color:#999;border-color:#e5e5e5}.uk-input::placeholder{color:#999}.uk-textarea::placeholder{color:#999}.uk-form-small{font-size:.875rem}.uk-form-small:not(textarea):not([multiple]):not([size]){height:30px;padding-right:8px;padding-left:8px}[multiple].uk-form-small,[size].uk-form-small,textarea.uk-form-small{padding:5px 8px}.uk-form-small:not(select):not(input):not(textarea){line-height:28px}.uk-form-large{font-size:1.25rem}.uk-form-large:not(textarea):not([multiple]):not([size]){height:55px;padding-right:12px;padding-left:12px}[multiple].uk-form-large,[size].uk-form-large,textarea.uk-form-large{padding:7px 12px}.uk-form-large:not(select):not(input):not(textarea){line-height:53px}.uk-form-danger,.uk-form-danger:focus{color:#f0506e;border-color:#f0506e}.uk-form-success,.uk-form-success:focus{color:#32d296;border-color:#32d296}.uk-form-blank{background:0 0;border-color:transparent}.uk-form-blank:focus{border-color:#e5e5e5;border-style:solid}input.uk-form-width-xsmall{width:50px}select.uk-form-width-xsmall{width:75px}.uk-form-width-small{width:130px}.uk-form-width-medium{width:200px}.uk-form-width-large{width:500px}.uk-select:not([multiple]):not([size]){-webkit-appearance:none;-moz-appearance:none;padding-left:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:0 50%}.uk-select:not([multiple]):not([size]) option{color:#666}.uk-select:not([multiple]):not([size]):disabled{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-input[list]{padding-left:20px;background-repeat:no-repeat;background-position:0 50%}.uk-input[list]:focus,.uk-input[list]:hover{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-input[list]::-webkit-calendar-picker-indicator{display:none!important}.uk-checkbox,.uk-radio{display:inline-block;height:16px;width:16px;overflow:hidden;margin-top:-4px;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;border:1px solid #ccc;transition:.2s ease-in-out;transition-property:background-color,border}.uk-radio{border-radius:50%}.uk-checkbox:focus,.uk-radio:focus{background-color:rgba(0,0,0,0);outline:0;border-color:#1e87f0}.uk-checkbox:checked,.uk-checkbox:indeterminate,.uk-radio:checked{background-color:#1e87f0;border-color:transparent}.uk-checkbox:checked:focus,.uk-checkbox:indeterminate:focus,.uk-radio:checked:focus{background-color:#0e6dcd}.uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23fff%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23fff%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23fff%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled,.uk-radio:disabled{background-color:#f8f8f8;border-color:#e5e5e5}.uk-radio:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23999%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:disabled:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23999%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-legend{width:100%;color:inherit;padding:0;font-size:1.5rem;line-height:1.4}.uk-form-custom{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-form-custom input[type=file],.uk-form-custom select{position:absolute;top:0;z-index:1;width:100%;height:100%;right:0;-webkit-appearance:none;opacity:0;cursor:pointer}.uk-form-custom input[type=file]{font-size:500px;overflow:hidden}.uk-form-label{color:#333;font-size:.875rem}.uk-form-stacked .uk-form-label{display:block;margin-bottom:5px}@media (max-width:959px){.uk-form-horizontal .uk-form-label{display:block;margin-bottom:5px}}@media (min-width:960px){.uk-form-horizontal .uk-form-label{width:200px;margin-top:7px;float:right}.uk-form-horizontal .uk-form-controls{margin-right:215px}.uk-form-horizontal .uk-form-controls-text{padding-top:7px}}.uk-form-icon{position:absolute;top:0;bottom:0;right:0;width:40px;display:inline-flex;justify-content:center;align-items:center;color:#999}.uk-form-icon:hover{color:#666}.uk-form-icon:not(a):not(button):not(input){pointer-events:none}.uk-form-icon:not(.uk-form-icon-flip)~.uk-input{padding-right:40px!important}.uk-form-icon-flip{left:0;right:auto}.uk-form-icon-flip~.uk-input{padding-left:40px!important}.uk-button{margin:0;border:none;overflow:visible;font:inherit;color:inherit;text-transform:none;-webkit-appearance:none;border-radius:0;display:inline-block;box-sizing:border-box;padding:0 30px;vertical-align:middle;font-size:.875rem;line-height:38px;text-align:center;text-decoration:none;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color,border-color}.uk-button:not(:disabled){cursor:pointer}.uk-button::-moz-focus-inner{border:0;padding:0}.uk-button:hover{text-decoration:none}.uk-button-default{background-color:transparent;color:#333;border:1px solid #e5e5e5}.uk-button-default:hover{background-color:transparent;color:#333;border-color:#b2b2b2}.uk-button-default.uk-active,.uk-button-default:active{background-color:transparent;color:#333;border-color:#999}.uk-button-primary{background-color:#1e87f0;color:#fff;border:1px solid transparent}.uk-button-primary:hover{background-color:#0f7ae5;color:#fff}.uk-button-primary.uk-active,.uk-button-primary:active{background-color:#0e6dcd;color:#fff}.uk-button-secondary{background-color:#222;color:#fff;border:1px solid transparent}.uk-button-secondary:hover{background-color:#151515;color:#fff}.uk-button-secondary.uk-active,.uk-button-secondary:active{background-color:#080808;color:#fff}.uk-button-danger{background-color:#f0506e;color:#fff;border:1px solid transparent}.uk-button-danger:hover{background-color:#ee395b;color:#fff}.uk-button-danger.uk-active,.uk-button-danger:active{background-color:#ec2147;color:#fff}.uk-button-danger:disabled,.uk-button-default:disabled,.uk-button-primary:disabled,.uk-button-secondary:disabled{background-color:transparent;color:#999;border-color:#e5e5e5}.uk-button-small{padding:0 15px;line-height:28px;font-size:.875rem}.uk-button-large{padding:0 40px;line-height:53px;font-size:.875rem}.uk-button-text{padding:0;line-height:1.5;background:0 0;color:#333;position:relative}.uk-button-text::before{content:"";position:absolute;bottom:0;right:0;left:100%;border-bottom:1px solid currentColor;transition:left .3s ease-out}.uk-button-text:hover{color:#333}.uk-button-text:hover::before{left:0}.uk-button-text:disabled{color:#999}.uk-button-text:disabled::before{display:none}.uk-button-link{padding:0;line-height:1.5;background:0 0;color:#333}.uk-button-link:hover{color:#999;text-decoration:none}.uk-button-link:disabled{color:#999;text-decoration:none}.uk-button-group{display:inline-flex;vertical-align:middle;position:relative}.uk-button-group>.uk-button:nth-child(n+2),.uk-button-group>div:nth-child(n+2) .uk-button{margin-right:-1px}.uk-button-group .uk-button.uk-active,.uk-button-group .uk-button:active,.uk-button-group .uk-button:focus,.uk-button-group .uk-button:hover{position:relative;z-index:1}.uk-progress{vertical-align:baseline;display:block;width:100%;border:0;background-color:#f8f8f8;margin-bottom:20px;height:15px;border-radius:500px;overflow:hidden}*+.uk-progress{margin-top:20px}.uk-progress::-webkit-progress-bar{background-color:transparent}.uk-progress::-webkit-progress-value{background-color:#1e87f0;transition:width .6s ease}.uk-progress::-moz-progress-bar{background-color:#1e87f0;transition:width .6s ease}.uk-section{display:flow-root;box-sizing:border-box;padding-top:40px;padding-bottom:40px}@media (min-width:960px){.uk-section{padding-top:70px;padding-bottom:70px}}.uk-section>:last-child{margin-bottom:0}.uk-section-xsmall{padding-top:20px;padding-bottom:20px}.uk-section-small{padding-top:40px;padding-bottom:40px}.uk-section-large{padding-top:70px;padding-bottom:70px}@media (min-width:960px){.uk-section-large{padding-top:140px;padding-bottom:140px}}.uk-section-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width:960px){.uk-section-xlarge{padding-top:210px;padding-bottom:210px}}.uk-section-default{--uk-inverse:dark;background:#fff}.uk-section-muted{--uk-inverse:dark;background:#f8f8f8}.uk-section-primary{--uk-inverse:light;background:#1e87f0}.uk-section-secondary{--uk-inverse:light;background:#222}.uk-container{display:flow-root;box-sizing:content-box;max-width:1200px;margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px}@media (min-width:640px){.uk-container{padding-right:30px;padding-left:30px}}@media (min-width:960px){.uk-container{padding-right:40px;padding-left:40px}}.uk-container>:last-child{margin-bottom:0}.uk-container .uk-container{padding-right:0;padding-left:0}.uk-container-xsmall{max-width:750px}.uk-container-small{max-width:900px}.uk-container-large{max-width:1400px}.uk-container-xlarge{max-width:1600px}.uk-container-expand{max-width:none}.uk-container-expand-right{margin-right:0}.uk-container-expand-left{margin-left:0}@media (min-width:640px){.uk-container-expand-left.uk-container-xsmall,.uk-container-expand-right.uk-container-xsmall{max-width:calc(50% + (750px / 2) - 30px)}.uk-container-expand-left.uk-container-small,.uk-container-expand-right.uk-container-small{max-width:calc(50% + (900px / 2) - 30px)}}@media (min-width:960px){.uk-container-expand-left,.uk-container-expand-right{max-width:calc(50% + (1200px / 2) - 40px)}.uk-container-expand-left.uk-container-xsmall,.uk-container-expand-right.uk-container-xsmall{max-width:calc(50% + (750px / 2) - 40px)}.uk-container-expand-left.uk-container-small,.uk-container-expand-right.uk-container-small{max-width:calc(50% + (900px / 2) - 40px)}.uk-container-expand-left.uk-container-large,.uk-container-expand-right.uk-container-large{max-width:calc(50% + (1400px / 2) - 40px)}.uk-container-expand-left.uk-container-xlarge,.uk-container-expand-right.uk-container-xlarge{max-width:calc(50% + (1600px / 2) - 40px)}}.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 15px)}.uk-container-item-padding-remove-right{margin-right:-15px}.uk-container-item-padding-remove-left{margin-left:-15px}@media (min-width:640px){.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 30px)}.uk-container-item-padding-remove-right{margin-right:-30px}.uk-container-item-padding-remove-left{margin-left:-30px}}@media (min-width:960px){.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 40px)}.uk-container-item-padding-remove-right{margin-right:-40px}.uk-container-item-padding-remove-left{margin-left:-40px}}.uk-tile{display:flow-root;position:relative;box-sizing:border-box;padding-right:15px;padding-left:15px;padding-top:40px;padding-bottom:40px}@media (min-width:640px){.uk-tile{padding-right:30px;padding-left:30px}}@media (min-width:960px){.uk-tile{padding-right:40px;padding-left:40px;padding-top:70px;padding-bottom:70px}}.uk-tile>:last-child{margin-bottom:0}.uk-tile-xsmall{padding-top:20px;padding-bottom:20px}.uk-tile-small{padding-top:40px;padding-bottom:40px}.uk-tile-large{padding-top:70px;padding-bottom:70px}@media (min-width:960px){.uk-tile-large{padding-top:140px;padding-bottom:140px}}.uk-tile-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width:960px){.uk-tile-xlarge{padding-top:210px;padding-bottom:210px}}.uk-tile-default{--uk-inverse:dark;background-color:#fff}.uk-tile-muted{--uk-inverse:dark;background-color:#f8f8f8}.uk-tile-primary{--uk-inverse:light;background-color:#1e87f0}.uk-tile-secondary{--uk-inverse:light;background-color:#222}.uk-card{position:relative;box-sizing:border-box;transition:box-shadow .1s ease-in-out}.uk-card-body{display:flow-root;padding:30px 30px}.uk-card-header{display:flow-root;padding:15px 30px}.uk-card-footer{display:flow-root;padding:15px 30px}@media (min-width:1200px){.uk-card-body{padding:40px 40px}.uk-card-header{padding:20px 40px}.uk-card-footer{padding:20px 40px}}.uk-card-body>:last-child,.uk-card-footer>:last-child,.uk-card-header>:last-child{margin-bottom:0}.uk-card-title{font-size:1.5rem;line-height:1.4}.uk-card-badge{position:absolute;top:15px;left:15px;z-index:1;height:22px;padding:0 10px;background:#1e87f0;color:#fff;font-size:.875rem;display:flex;justify-content:center;align-items:center;line-height:0;border-radius:2px;text-transform:uppercase}.uk-card-badge:first-child+*{margin-top:0}.uk-card-hover:not(.uk-card-default):not(.uk-card-primary):not(.uk-card-secondary):hover{background-color:#fff;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-default{--uk-inverse:dark;background-color:#fff;color:#666;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-default .uk-card-title{color:#333}.uk-card-default.uk-card-hover:hover{background-color:#fff;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-default .uk-card-header{border-bottom:1px solid #e5e5e5}.uk-card-default .uk-card-footer{border-top:1px solid #e5e5e5}.uk-card-primary{--uk-inverse:light;background-color:#1e87f0;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-primary .uk-card-title{color:#fff}.uk-card-primary.uk-card-hover:hover{background-color:#1e87f0;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-secondary{--uk-inverse:light;background-color:#222;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-secondary .uk-card-title{color:#fff}.uk-card-secondary.uk-card-hover:hover{background-color:#222;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-small .uk-card-body,.uk-card-small.uk-card-body{padding:20px 20px}.uk-card-small .uk-card-header{padding:13px 20px}.uk-card-small .uk-card-footer{padding:13px 20px}@media (min-width:1200px){.uk-card-large .uk-card-body,.uk-card-large.uk-card-body{padding:70px 70px}.uk-card-large .uk-card-header{padding:35px 70px}.uk-card-large .uk-card-footer{padding:35px 70px}}.uk-card-body>.uk-nav-default{margin-right:-30px;margin-left:-30px}.uk-card-body>.uk-nav-default:only-child{margin-top:-15px;margin-bottom:-15px}.uk-card-body>.uk-nav-default .uk-nav-divider,.uk-card-body>.uk-nav-default .uk-nav-header,.uk-card-body>.uk-nav-default>li>a{padding-right:30px;padding-left:30px}.uk-card-body>.uk-nav-default .uk-nav-sub{padding-right:45px}@media (min-width:1200px){.uk-card-body>.uk-nav-default{margin-right:-40px;margin-left:-40px}.uk-card-body>.uk-nav-default:only-child{margin-top:-25px;margin-bottom:-25px}.uk-card-body>.uk-nav-default .uk-nav-divider,.uk-card-body>.uk-nav-default .uk-nav-header,.uk-card-body>.uk-nav-default>li>a{padding-right:40px;padding-left:40px}.uk-card-body>.uk-nav-default .uk-nav-sub{padding-right:55px}}.uk-card-small>.uk-nav-default{margin-right:-20px;margin-left:-20px}.uk-card-small>.uk-nav-default:only-child{margin-top:-5px;margin-bottom:-5px}.uk-card-small>.uk-nav-default .uk-nav-divider,.uk-card-small>.uk-nav-default .uk-nav-header,.uk-card-small>.uk-nav-default>li>a{padding-right:20px;padding-left:20px}.uk-card-small>.uk-nav-default .uk-nav-sub{padding-right:35px}@media (min-width:1200px){.uk-card-large>.uk-nav-default{margin:0}.uk-card-large>.uk-nav-default:only-child{margin:0}.uk-card-large>.uk-nav-default .uk-nav-divider,.uk-card-large>.uk-nav-default .uk-nav-header,.uk-card-large>.uk-nav-default>li>a{padding-right:0;padding-left:0}.uk-card-large>.uk-nav-default .uk-nav-sub{padding-right:15px}}.uk-close{color:#999;transition:.1s ease-in-out;transition-property:color,opacity}.uk-close:hover{color:#666}.uk-spinner>*{animation:uk-spinner-rotate 1.4s linear infinite}@keyframes uk-spinner-rotate{0%{transform:rotate(0)}100%{transform:rotate(-270deg)}}.uk-spinner>*>*{stroke-dasharray:88px;stroke-dashoffset:0;transform-origin:center;animation:uk-spinner-dash 1.4s ease-in-out infinite;stroke-width:1;stroke-linecap:round}@keyframes uk-spinner-dash{0%{stroke-dashoffset:-88px}50%{stroke-dashoffset:-22px;transform:rotate(-135deg)}100%{stroke-dashoffset:-88px;transform:rotate(-450deg)}}.uk-totop{padding:5px;color:#999;transition:color .1s ease-in-out}.uk-totop:hover{color:#666}.uk-totop:active{color:#333}.uk-marker{padding:5px;background:#222;color:#fff;border-radius:500px}.uk-marker:hover{color:#fff}.uk-alert{position:relative;margin-bottom:20px;padding:15px 15px 15px 29px;background:#f8f8f8;color:#666}*+.uk-alert{margin-top:20px}.uk-alert>:last-child{margin-bottom:0}.uk-alert-close{position:absolute;top:20px;left:15px;color:inherit;opacity:.4}.uk-alert-close:first-child+*{margin-top:0}.uk-alert-close:hover{color:inherit;opacity:.8}.uk-alert-primary{background:#d8eafc;color:#1e87f0}.uk-alert-success{background:#edfbf6;color:#32d296}.uk-alert-warning{background:#fff6ee;color:#faa05a}.uk-alert-danger{background:#fef4f6;color:#f0506e}.uk-alert h1,.uk-alert h2,.uk-alert h3,.uk-alert h4,.uk-alert h5,.uk-alert h6{color:inherit}.uk-alert a:not([class]){color:inherit;text-decoration:underline}.uk-alert a:not([class]):hover{color:inherit;text-decoration:underline}.uk-placeholder{margin-bottom:20px;padding:30px 30px;background:0 0;border:1px dashed #e5e5e5}*+.uk-placeholder{margin-top:20px}.uk-placeholder>:last-child{margin-bottom:0}.uk-badge{box-sizing:border-box;min-width:18px;height:18px;padding:0 5px;border-radius:500px;vertical-align:middle;background:#1e87f0;color:#fff!important;font-size:11px;display:inline-flex;justify-content:center;align-items:center;line-height:0}.uk-badge:hover{text-decoration:none}.uk-label{display:inline-block;padding:0 10px;background:#1e87f0;line-height:1.5;font-size:.875rem;color:#fff;vertical-align:middle;white-space:nowrap;border-radius:2px;text-transform:uppercase}.uk-label-success{background-color:#32d296;color:#fff}.uk-label-warning{background-color:#faa05a;color:#fff}.uk-label-danger{background-color:#f0506e;color:#fff}.uk-overlay{padding:30px 30px}.uk-overlay>:last-child{margin-bottom:0}.uk-overlay-default{--uk-inverse:dark;background:rgba(255,255,255,.8)}.uk-overlay-primary{--uk-inverse:light;background:rgba(34,34,34,.8)}.uk-article{display:flow-root}.uk-article>:last-child{margin-bottom:0}.uk-article+.uk-article{margin-top:70px}.uk-article-title{font-size:2.23125rem;line-height:1.2}@media (min-width:960px){.uk-article-title{font-size:2.625rem}}.uk-article-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-article-meta a{color:#999}.uk-article-meta a:hover{color:#666;text-decoration:none}.uk-comment-body{display:flow-root;overflow-wrap:break-word;word-wrap:break-word}.uk-comment-header{display:flow-root;margin-bottom:20px}.uk-comment-body>:last-child,.uk-comment-header>:last-child{margin-bottom:0}.uk-comment-title{font-size:1.25rem;line-height:1.4}.uk-comment-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-comment-list{padding:0;list-style:none}.uk-comment-list>:nth-child(n+2){margin-top:70px}.uk-comment-list .uk-comment~ul{margin:70px 0 0 0;padding-right:30px;list-style:none}@media (min-width:960px){.uk-comment-list .uk-comment~ul{padding-right:100px}}.uk-comment-list .uk-comment~ul>:nth-child(n+2){margin-top:70px}.uk-comment-primary{padding:30px;background-color:#f8f8f8}.uk-search{display:inline-block;position:relative;max-width:100%;margin:0}.uk-search-input::-webkit-search-cancel-button,.uk-search-input::-webkit-search-decoration{-webkit-appearance:none}.uk-search-input::-moz-placeholder{opacity:1}.uk-search-input{box-sizing:border-box;margin:0;border-radius:0;font:inherit;overflow:visible;-webkit-appearance:none;vertical-align:middle;width:100%;border:none;color:#666}.uk-search-input:focus{outline:0}.uk-search-input::placeholder{color:#999}.uk-search .uk-search-icon{position:absolute;top:0;bottom:0;right:0;display:inline-flex;justify-content:center;align-items:center;color:#999}.uk-search .uk-search-icon:hover{color:#999}.uk-search .uk-search-icon:not(a):not(button):not(input){pointer-events:none}.uk-search .uk-search-icon-flip{left:0;right:auto}.uk-search-default{width:240px}.uk-search-default .uk-search-input{height:40px;padding-right:10px;padding-left:10px;background:0 0;border:1px solid #e5e5e5}.uk-search-default .uk-search-input:focus{background-color:rgba(0,0,0,0);border-color:#1e87f0}.uk-search-default .uk-search-icon{padding-right:10px;padding-left:10px}.uk-search-default:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-right:40px}.uk-search-default:has(.uk-search-icon-flip) .uk-search-input{padding-left:40px}.uk-search-navbar{width:240px}.uk-search-navbar .uk-search-input{height:40px;padding-right:10px;padding-left:10px;background:#fff;border:1px solid #e5e5e5}.uk-search-navbar .uk-search-input:focus{background-color:#fff;border-color:#1e87f0}.uk-search-navbar .uk-search-icon{padding-right:10px;padding-left:10px}.uk-search-navbar:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-right:40px}.uk-search-navbar:has(.uk-search-icon-flip) .uk-search-input{padding-left:40px}.uk-search-medium{width:400px}.uk-search-medium .uk-search-input{height:55px;padding-right:12px;padding-left:12px;background:0 0;font-size:1.5rem;border:1px solid #e5e5e5}.uk-search-medium .uk-search-input:focus{background-color:rgba(0,0,0,0);border-color:#1e87f0}.uk-search-medium .uk-search-icon{padding-right:12px;padding-left:12px}.uk-search-medium:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-right:48px}.uk-search-medium:has(.uk-search-icon-flip) .uk-search-input{padding-left:48px}.uk-search-large{width:500px}.uk-search-large .uk-search-input{height:90px;padding-right:20px;padding-left:20px;background:0 0;font-size:2.625rem;border:1px solid #e5e5e5}.uk-search-large .uk-search-input:focus{background-color:rgba(0,0,0,0);border-color:#1e87f0}.uk-search-large .uk-search-icon{padding-right:20px;padding-left:20px}.uk-search-large:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-right:80px}.uk-search-large:has(.uk-search-icon-flip) .uk-search-input{padding-left:80px}.uk-search-toggle{color:#999}.uk-search-toggle:hover{color:#666}.uk-accordion{padding:0;list-style:none}.uk-accordion>:nth-child(n+2){margin-top:20px}.uk-accordion-title{display:block;font-size:1.25rem;line-height:1.4;color:#333;overflow:hidden}.uk-accordion-title::before{content:"";width:1.4em;height:1.4em;margin-right:10px;float:left;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-open>.uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-accordion-title:hover{color:#666;text-decoration:none}.uk-accordion-content{display:flow-root;margin-top:20px}.uk-accordion-content>:last-child{margin-bottom:0}.uk-drop{display:none;position:absolute;z-index:1020;--uk-position-offset:20px;--uk-position-viewport-offset:15px;box-sizing:border-box;width:300px}.uk-drop.uk-open{display:block}.uk-drop-stack .uk-drop-grid>*{width:100%!important}.uk-drop-parent-icon{margin-right:.25em;transition:transform .3s ease-out}[aria-expanded=true]>.uk-drop-parent-icon{transform:rotateX(180deg)}.uk-dropbar{--uk-position-offset:0;--uk-position-shift-offset:0;--uk-position-viewport-offset:0;--uk-inverse:dark;width:auto;padding:25px 15px 25px 15px;background:#fff;color:#666}.uk-dropbar>:last-child{margin-bottom:0}@media (min-width:640px){.uk-dropbar{padding-right:30px;padding-left:30px}}@media (min-width:960px){.uk-dropbar{padding-right:40px;padding-left:40px}}.uk-dropbar :focus-visible{outline-color:#333!important}.uk-dropbar-large{padding-top:40px;padding-bottom:40px}.uk-dropbar-top{box-shadow:0 12px 7px -6px rgba(0,0,0,.05)}.uk-dropbar-bottom{box-shadow:0 -12px 7px -6px rgba(0,0,0,.05)}.uk-dropbar-right{box-shadow:-12px 0 7px -6px rgba(0,0,0,.05)}.uk-dropbar-left{box-shadow:12px 0 7px -6px rgba(0,0,0,.05)}.uk-dropnav-dropbar{position:absolute;z-index:980;padding:0;right:0;left:0}.uk-modal{display:none;position:fixed;top:0;left:0;bottom:0;right:0;z-index:1010;overflow-y:auto;padding:15px 15px;background:rgba(0,0,0,.6);opacity:0;transition:opacity .15s linear}@media (min-width:640px){.uk-modal{padding:50px 30px}}@media (min-width:960px){.uk-modal{padding-right:40px;padding-left:40px}}.uk-modal.uk-open{opacity:1}.uk-modal-page{overflow:hidden}.uk-modal-dialog{position:relative;box-sizing:border-box;margin:0 auto;width:600px;max-width:100%!important;background:#fff;opacity:0;transform:translateY(-100px);transition:.3s linear;transition-property:opacity,transform}.uk-open>.uk-modal-dialog{opacity:1;transform:translateY(0)}.uk-modal-container .uk-modal-dialog{width:1200px}.uk-modal-full{padding:0;background:0 0}.uk-modal-full .uk-modal-dialog{margin:0;width:100%;max-width:100%;transform:translateY(0)}.uk-modal-body{display:flow-root;padding:20px 20px}.uk-modal-header{display:flow-root;padding:10px 20px;background:#fff;border-bottom:1px solid #e5e5e5}.uk-modal-footer{display:flow-root;padding:10px 20px;background:#fff;border-top:1px solid #e5e5e5}@media (min-width:640px){.uk-modal-body{padding:30px 30px}.uk-modal-header{padding:15px 30px}.uk-modal-footer{padding:15px 30px}}.uk-modal-body>:last-child,.uk-modal-footer>:last-child,.uk-modal-header>:last-child{margin-bottom:0}.uk-modal-title{font-size:2rem;line-height:1.3}[class*=uk-modal-close-]{position:absolute;z-index:1010;top:10px;left:10px;padding:5px}[class*=uk-modal-close-]:first-child+*{margin-top:0}.uk-modal-close-outside{top:0;left:-5px;transform:translate(0,-100%);color:#fff}.uk-modal-close-outside:hover{color:#fff}@media (min-width:960px){.uk-modal-close-outside{left:0;transform:translate(-100%,-100%)}}.uk-modal-close-full{top:0;left:0;padding:10px;background:#fff}@media (min-width:960px){.uk-modal-close-full{padding:20px}}.uk-slideshow{-webkit-tap-highlight-color:transparent}.uk-slideshow-items{position:relative;z-index:0;margin:0;padding:0;list-style:none;overflow:hidden;-webkit-touch-callout:none;touch-action:pan-y}.uk-slideshow-items>*{position:absolute;top:0;right:0;left:0;bottom:0;overflow:hidden;will-change:transform,opacity}.uk-slideshow-items>:not(.uk-active){display:none}.uk-slider{-webkit-tap-highlight-color:transparent}.uk-slider-container{overflow:hidden;overflow:clip}.uk-slider-container-offset{margin:-11px -25px -39px -25px;padding:11px 25px 39px 25px}.uk-slider-items{will-change:transform;position:relative;touch-action:pan-y}.uk-slider-items:not(.uk-grid){display:flex;margin:0;padding:0;list-style:none;-webkit-touch-callout:none}.uk-slider-items.uk-grid{flex-wrap:nowrap}.uk-slider-items>*{flex:none!important;box-sizing:border-box;max-width:100%;position:relative}.uk-sticky{position:relative;z-index:980;box-sizing:border-box}.uk-sticky-fixed{margin:0!important}.uk-sticky[class*=uk-animation-]{animation-duration:.2s}.uk-sticky.uk-animation-reverse{animation-duration:.2s}.uk-sticky-placeholder{pointer-events:none}.uk-offcanvas{display:none;position:fixed;top:0;bottom:0;right:0;z-index:1000}.uk-offcanvas-flip .uk-offcanvas{left:0;right:auto}.uk-offcanvas-bar{--uk-inverse:light;position:absolute;top:0;bottom:0;right:-270px;box-sizing:border-box;width:270px;padding:20px 20px;background:#222;overflow-y:auto}@media (min-width:640px){.uk-offcanvas-bar{right:-350px;width:350px;padding:30px 30px}}.uk-offcanvas-flip .uk-offcanvas-bar{right:auto;left:-270px}@media (min-width:640px){.uk-offcanvas-flip .uk-offcanvas-bar{left:-350px}}.uk-open>.uk-offcanvas-bar{right:0}.uk-offcanvas-flip .uk-open>.uk-offcanvas-bar{right:auto;left:0}.uk-offcanvas-bar-animation{transition:right .3s ease-out}.uk-offcanvas-flip .uk-offcanvas-bar-animation{transition-property:left}.uk-offcanvas-reveal{position:absolute;top:0;bottom:0;right:0;width:0;overflow:hidden;transition:width .3s ease-out}.uk-offcanvas-reveal .uk-offcanvas-bar{right:0}.uk-offcanvas-flip .uk-offcanvas-reveal .uk-offcanvas-bar{right:auto;left:0}.uk-open>.uk-offcanvas-reveal{width:270px}@media (min-width:640px){.uk-open>.uk-offcanvas-reveal{width:350px}}.uk-offcanvas-flip .uk-offcanvas-reveal{left:0;right:auto}.uk-offcanvas-close{position:absolute;z-index:1000;top:5px;left:5px;padding:5px}@media (min-width:640px){.uk-offcanvas-close{top:10px;left:10px}}.uk-offcanvas-close:first-child+*{margin-top:0}.uk-offcanvas-overlay{width:100vw;touch-action:none}.uk-offcanvas-overlay::before{content:"";position:absolute;top:0;bottom:0;right:0;left:0;background:rgba(0,0,0,.1);opacity:0;transition:opacity .15s linear}.uk-offcanvas-overlay.uk-open::before{opacity:1}.uk-offcanvas-container,.uk-offcanvas-page{overflow-x:hidden;overflow-x:clip}.uk-offcanvas-container{position:relative;right:0;transition:right .3s ease-out;box-sizing:border-box;width:100%}:not(.uk-offcanvas-flip).uk-offcanvas-container-animation{right:270px}.uk-offcanvas-flip.uk-offcanvas-container-animation{right:-270px}@media (min-width:640px){:not(.uk-offcanvas-flip).uk-offcanvas-container-animation{right:350px}.uk-offcanvas-flip.uk-offcanvas-container-animation{right:-350px}}.uk-switcher{margin:0;padding:0;list-style:none}.uk-switcher>:not(.uk-active){display:none}.uk-switcher>*>:last-child{margin-bottom:0}.uk-leader{overflow:hidden}.uk-leader-fill::after{display:inline-block;margin-right:15px;width:0;content:attr(data-fill);white-space:nowrap}.uk-leader-fill.uk-leader-hide::after{display:none}:root{--uk-leader-fill-content:.}.uk-notification{position:fixed;top:10px;right:10px;z-index:1040;box-sizing:border-box;width:350px}.uk-notification-bottom-left,.uk-notification-top-left{right:auto;left:10px}.uk-notification-bottom-center,.uk-notification-top-center{right:50%;margin-right:-175px}.uk-notification-bottom-center,.uk-notification-bottom-left,.uk-notification-bottom-right{top:auto;bottom:10px}@media (max-width:639px){.uk-notification{right:10px;left:10px;width:auto;margin:0}}.uk-notification-message{position:relative;padding:15px;background:#f8f8f8;color:#666;font-size:1.25rem;line-height:1.4;cursor:pointer}*+.uk-notification-message{margin-top:10px}.uk-notification-close{display:none;position:absolute;top:20px;left:15px}.uk-notification-message:hover .uk-notification-close{display:block}.uk-notification-message-primary{color:#1e87f0}.uk-notification-message-success{color:#32d296}.uk-notification-message-warning{color:#faa05a}.uk-notification-message-danger{color:#f0506e}.uk-tooltip{display:none;position:absolute;z-index:1030;--uk-position-offset:10px;--uk-position-viewport-offset:10;top:0;box-sizing:border-box;max-width:200px;padding:3px 6px;background:#666;border-radius:2px;color:#fff;font-size:12px}.uk-tooltip.uk-active{display:block}.uk-sortable{position:relative}.uk-sortable>:last-child{margin-bottom:0}.uk-sortable-drag{position:fixed!important;z-index:1050!important;pointer-events:none}.uk-sortable-placeholder{opacity:0;pointer-events:none}.uk-sortable-empty{min-height:50px}.uk-sortable-handle:hover{cursor:move}.uk-countdown-number{font-variant-numeric:tabular-nums;font-size:2rem;line-height:.8}@media (min-width:640px){.uk-countdown-number{font-size:4rem}}@media (min-width:960px){.uk-countdown-number{font-size:6rem}}.uk-countdown-separator{font-size:1rem;line-height:1.6}@media (min-width:640px){.uk-countdown-separator{font-size:2rem}}@media (min-width:960px){.uk-countdown-separator{font-size:3rem}}.uk-thumbnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-right:-15px}.uk-thumbnav>*{padding-right:15px}.uk-thumbnav>*>*{display:inline-block;position:relative}.uk-thumbnav>*>::after{content:"";position:absolute;top:0;bottom:0;right:0;left:0;background-image:linear-gradient(-180deg,rgba(255,255,255,0),rgba(255,255,255,.4));transition:opacity .1s ease-in-out}.uk-thumbnav>*>:hover::after{opacity:0}.uk-thumbnav>.uk-active>::after{opacity:0}.uk-thumbnav-vertical{flex-direction:column;margin-right:0;margin-top:-15px}.uk-thumbnav-vertical>*{padding-right:0;padding-top:15px}.uk-iconnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-right:-10px}.uk-iconnav>*{padding-right:10px}.uk-iconnav>*>a{display:flex;align-items:center;column-gap:.25em;line-height:0;color:#999;text-decoration:none;font-size:.875rem;transition:.1s ease-in-out;transition-property:color,background-color}.uk-iconnav>*>a:hover{color:#666}.uk-iconnav>.uk-active>a{color:#666}.uk-iconnav-vertical{flex-direction:column;margin-right:0;margin-top:-10px}.uk-iconnav-vertical>*{padding-right:0;padding-top:10px}.uk-grid{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none}.uk-grid>*{margin:0}.uk-grid>*>:last-child{margin-bottom:0}.uk-grid{margin-right:-30px}.uk-grid>*{padding-right:30px}*+.uk-grid-margin,.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin{margin-top:30px}@media (min-width:1200px){.uk-grid{margin-right:-40px}.uk-grid>*{padding-right:40px}*+.uk-grid-margin,.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin{margin-top:40px}}.uk-grid-column-small,.uk-grid-small{margin-right:-15px}.uk-grid-column-small>*,.uk-grid-small>*{padding-right:15px}*+.uk-grid-margin-small,.uk-grid+.uk-grid-row-small,.uk-grid+.uk-grid-small,.uk-grid-row-small>.uk-grid-margin,.uk-grid-small>.uk-grid-margin{margin-top:15px}.uk-grid-column-medium,.uk-grid-medium{margin-right:-30px}.uk-grid-column-medium>*,.uk-grid-medium>*{padding-right:30px}*+.uk-grid-margin-medium,.uk-grid+.uk-grid-medium,.uk-grid+.uk-grid-row-medium,.uk-grid-medium>.uk-grid-margin,.uk-grid-row-medium>.uk-grid-margin{margin-top:30px}.uk-grid-column-large,.uk-grid-large{margin-right:-40px}.uk-grid-column-large>*,.uk-grid-large>*{padding-right:40px}*+.uk-grid-margin-large,.uk-grid+.uk-grid-large,.uk-grid+.uk-grid-row-large,.uk-grid-large>.uk-grid-margin,.uk-grid-row-large>.uk-grid-margin{margin-top:40px}@media (min-width:1200px){.uk-grid-column-large,.uk-grid-large{margin-right:-70px}.uk-grid-column-large>*,.uk-grid-large>*{padding-right:70px}*+.uk-grid-margin-large,.uk-grid+.uk-grid-large,.uk-grid+.uk-grid-row-large,.uk-grid-large>.uk-grid-margin,.uk-grid-row-large>.uk-grid-margin{margin-top:70px}}.uk-grid-collapse,.uk-grid-column-collapse{margin-right:0}.uk-grid-collapse>*,.uk-grid-column-collapse>*{padding-right:0}.uk-grid+.uk-grid-collapse,.uk-grid+.uk-grid-row-collapse,.uk-grid-collapse>.uk-grid-margin,.uk-grid-row-collapse>.uk-grid-margin{margin-top:0}.uk-grid-divider>*{position:relative}.uk-grid-divider>:not(.uk-first-column)::before{content:"";position:absolute;top:0;bottom:0;border-right:1px solid #e5e5e5}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{content:"";position:absolute;right:0;left:0;border-top:1px solid #e5e5e5}.uk-grid-divider{margin-right:-60px}.uk-grid-divider>*{padding-right:60px}.uk-grid-divider>:not(.uk-first-column)::before{right:30px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-30px;right:60px}@media (min-width:1200px){.uk-grid-divider{margin-right:-80px}.uk-grid-divider>*{padding-right:80px}.uk-grid-divider>:not(.uk-first-column)::before{right:40px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-40px;right:80px}}.uk-grid-divider.uk-grid-column-small,.uk-grid-divider.uk-grid-small{margin-right:-30px}.uk-grid-divider.uk-grid-column-small>*,.uk-grid-divider.uk-grid-small>*{padding-right:30px}.uk-grid-divider.uk-grid-column-small>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-small>:not(.uk-first-column)::before{right:15px}.uk-grid-divider.uk-grid-row-small.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin{margin-top:30px}.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin::before{top:-15px;right:30px}.uk-grid-divider.uk-grid-row-small.uk-grid-stack>.uk-grid-margin::before{top:-15px}.uk-grid-divider.uk-grid-column-small.uk-grid-stack>.uk-grid-margin::before{right:30px}.uk-grid-divider.uk-grid-column-medium,.uk-grid-divider.uk-grid-medium{margin-right:-60px}.uk-grid-divider.uk-grid-column-medium>*,.uk-grid-divider.uk-grid-medium>*{padding-right:60px}.uk-grid-divider.uk-grid-column-medium>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-medium>:not(.uk-first-column)::before{right:30px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-medium.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px;right:60px}.uk-grid-divider.uk-grid-row-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px}.uk-grid-divider.uk-grid-column-medium.uk-grid-stack>.uk-grid-margin::before{right:60px}.uk-grid-divider.uk-grid-column-large,.uk-grid-divider.uk-grid-large{margin-right:-80px}.uk-grid-divider.uk-grid-column-large>*,.uk-grid-divider.uk-grid-large>*{padding-right:80px}.uk-grid-divider.uk-grid-column-large>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{right:40px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-40px;right:80px}.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin::before{top:-40px}.uk-grid-divider.uk-grid-column-large.uk-grid-stack>.uk-grid-margin::before{right:80px}@media (min-width:1200px){.uk-grid-divider.uk-grid-column-large,.uk-grid-divider.uk-grid-large{margin-right:-140px}.uk-grid-divider.uk-grid-column-large>*,.uk-grid-divider.uk-grid-large>*{padding-right:140px}.uk-grid-divider.uk-grid-column-large>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{right:70px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin{margin-top:140px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-70px;right:140px}.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin::before{top:-70px}.uk-grid-divider.uk-grid-column-large.uk-grid-stack>.uk-grid-margin::before{right:140px}}.uk-grid-item-match,.uk-grid-match>*{display:flex;flex-wrap:wrap}.uk-grid-item-match>:not([class*=uk-width]),.uk-grid-match>*>:not([class*=uk-width]){box-sizing:border-box;width:100%;flex:auto}.uk-nav,.uk-nav ul{margin:0;padding:0;list-style:none}.uk-nav li>a{display:flex;align-items:center;column-gap:.25em;text-decoration:none}.uk-nav>li>a{padding:5px 0}ul.uk-nav-sub{padding:5px 15px 5px 0}.uk-nav-sub ul{padding-right:15px}.uk-nav-sub a{padding:2px 0}.uk-nav-parent-icon{margin-right:auto;transition:transform .3s ease-out}.uk-nav>li.uk-open>a .uk-nav-parent-icon{transform:rotateX(180deg)}.uk-nav-header{padding:5px 0;text-transform:uppercase;font-size:.875rem}.uk-nav-header:not(:first-child){margin-top:20px}.uk-nav .uk-nav-divider{margin:5px 0}.uk-nav-default{font-size:.875rem;line-height:1.5}.uk-nav-default>li>a{color:#999}.uk-nav-default>li>a:hover{color:#666}.uk-nav-default>li.uk-active>a{color:#333}.uk-nav-default .uk-nav-subtitle{font-size:12px}.uk-nav-default .uk-nav-header{color:#333}.uk-nav-default .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-default .uk-nav-sub{font-size:.875rem;line-height:1.5}.uk-nav-default .uk-nav-sub a{color:#999}.uk-nav-default .uk-nav-sub a:hover{color:#666}.uk-nav-default .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-primary{font-size:1.5rem;line-height:1.5}.uk-nav-primary>li>a{color:#999}.uk-nav-primary>li>a:hover{color:#666}.uk-nav-primary>li.uk-active>a{color:#333}.uk-nav-primary .uk-nav-subtitle{font-size:1.25rem}.uk-nav-primary .uk-nav-header{color:#333}.uk-nav-primary .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-primary .uk-nav-sub{font-size:1.25rem;line-height:1.5}.uk-nav-primary .uk-nav-sub a{color:#999}.uk-nav-primary .uk-nav-sub a:hover{color:#666}.uk-nav-primary .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-secondary{font-size:16px;line-height:1.5}.uk-nav-secondary>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider){margin-top:0}.uk-nav-secondary>li>a{color:#333;padding:10px 10px}.uk-nav-secondary>li>a:hover{color:#333;background-color:#f8f8f8}.uk-nav-secondary>li.uk-active>a{color:#333;background-color:#f8f8f8}.uk-nav-secondary .uk-nav-subtitle{font-size:.875rem;color:#999}.uk-nav-secondary>li>a:hover .uk-nav-subtitle{color:#666}.uk-nav-secondary>li.uk-active>a .uk-nav-subtitle{color:#333}.uk-nav-secondary .uk-nav-header{color:#333}.uk-nav-secondary .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-secondary .uk-nav-sub{font-size:.875rem;line-height:1.5}.uk-nav-secondary .uk-nav-sub a{color:#999}.uk-nav-secondary .uk-nav-sub a:hover{color:#666}.uk-nav-secondary .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-medium{font-size:2.8875rem;line-height:1}.uk-nav-large{font-size:3.4rem;line-height:1}.uk-nav-xlarge{font-size:4rem;line-height:1}@media (min-width:960px){.uk-nav-medium{font-size:3.5rem}.uk-nav-large{font-size:4rem}.uk-nav-xlarge{font-size:6rem}}@media (min-width:1200px){.uk-nav-medium{font-size:4rem}.uk-nav-large{font-size:6rem}.uk-nav-xlarge{font-size:8rem}}.uk-nav-center{text-align:center}.uk-nav-center li>a{justify-content:center}.uk-nav-center .uk-nav-sub,.uk-nav-center .uk-nav-sub ul{padding-right:0}.uk-nav-center .uk-nav-parent-icon{margin-right:.25em}.uk-nav.uk-nav-divider>:not(.uk-nav-header,.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider){margin-top:5px;padding-top:5px;border-top:1px solid #e5e5e5}.uk-navbar{display:flex;position:relative}.uk-navbar-container:not(.uk-navbar-transparent){background:#f8f8f8}.uk-navbar-left,.uk-navbar-right,[class*=uk-navbar-center]{display:flex;gap:15px;align-items:center}.uk-navbar-left{margin-right:auto}.uk-navbar-center:only-child{margin-right:auto;margin-left:auto;position:relative}.uk-navbar-center:not(:only-child){position:absolute;top:50%;right:50%;transform:translate(50%,-50%);width:max-content;box-sizing:border-box;z-index:990}.uk-navbar-center-left,.uk-navbar-center-right{position:absolute;top:0}.uk-navbar-center-right{left:calc(100% + 15px)}.uk-navbar-center-left{right:calc(100% + 15px)}[class*=uk-navbar-center-]{width:max-content;box-sizing:border-box}.uk-navbar-nav{display:flex;gap:15px;margin:0;padding:0;list-style:none}.uk-navbar-center:only-child,.uk-navbar-left,.uk-navbar-right{flex-wrap:wrap}.uk-navbar-item,.uk-navbar-nav>li>a,.uk-navbar-toggle{display:flex;justify-content:center;align-items:center;column-gap:.25em;box-sizing:border-box;min-height:80px;font-size:.875rem;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";text-decoration:none}.uk-navbar-nav>li>a{padding:0 0;color:#999;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color}.uk-navbar-nav>li:hover>a,.uk-navbar-nav>li>a[aria-expanded=true]{color:#666}.uk-navbar-nav>li>a:active{color:#333}.uk-navbar-nav>li.uk-active>a{color:#333}.uk-navbar-parent-icon{margin-right:4px;transition:transform .3s ease-out}.uk-navbar-nav>li>a[aria-expanded=true] .uk-navbar-parent-icon{transform:rotateX(180deg)}.uk-navbar-item{padding:0 0;color:#666}.uk-navbar-item>:last-child{margin-bottom:0}.uk-navbar-toggle{padding:0 0;color:#999}.uk-navbar-toggle:hover,.uk-navbar-toggle[aria-expanded=true]{color:#666;text-decoration:none}.uk-navbar-subtitle{font-size:.875rem}.uk-navbar-justify .uk-navbar-item,.uk-navbar-justify .uk-navbar-left,.uk-navbar-justify .uk-navbar-nav,.uk-navbar-justify .uk-navbar-nav>li,.uk-navbar-justify .uk-navbar-right,.uk-navbar-justify .uk-navbar-toggle{flex-grow:1}.uk-navbar-dropdown{--uk-position-offset:15px;--uk-position-shift-offset:0;--uk-position-viewport-offset:15px;--uk-inverse:dark;width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,.15)}.uk-navbar-dropdown>:last-child{margin-bottom:0}.uk-navbar-dropdown :focus-visible{outline-color:#333!important}.uk-navbar-dropdown .uk-drop-grid{margin-right:-30px}.uk-navbar-dropdown .uk-drop-grid>*{padding-right:30px}.uk-navbar-dropdown .uk-drop-grid>.uk-grid-margin{margin-top:30px}.uk-navbar-dropdown-width-2:not(.uk-drop-stack){width:400px}.uk-navbar-dropdown-width-3:not(.uk-drop-stack){width:600px}.uk-navbar-dropdown-width-4:not(.uk-drop-stack){width:800px}.uk-navbar-dropdown-width-5:not(.uk-drop-stack){width:1000px}.uk-navbar-dropdown-large{--uk-position-shift-offset:0;padding:40px}.uk-navbar-dropdown-dropbar{width:auto;background:0 0;padding:25px 0 25px 0;--uk-position-offset:0;--uk-position-shift-offset:0;--uk-position-viewport-offset:15px;box-shadow:none}@media (min-width:640px){.uk-navbar-dropdown-dropbar{--uk-position-viewport-offset:30px}}@media (min-width:960px){.uk-navbar-dropdown-dropbar{--uk-position-viewport-offset:40px}}.uk-navbar-dropdown-dropbar-large{--uk-position-shift-offset:0;padding-top:40px;padding-bottom:40px}.uk-navbar-dropdown-nav{font-size:.875rem}.uk-navbar-dropdown-nav>li>a{color:#999}.uk-navbar-dropdown-nav>li>a:hover{color:#666}.uk-navbar-dropdown-nav>li.uk-active>a{color:#333}.uk-navbar-dropdown-nav .uk-nav-subtitle{font-size:12px}.uk-navbar-dropdown-nav .uk-nav-header{color:#333}.uk-navbar-dropdown-nav .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-navbar-dropdown-nav .uk-nav-sub a{color:#999}.uk-navbar-dropdown-nav .uk-nav-sub a:hover{color:#666}.uk-navbar-dropdown-nav .uk-nav-sub li.uk-active>a{color:#333}.uk-navbar-container{transition:.1s ease-in-out;transition-property:background-color}@media (min-width:960px){.uk-navbar-left,.uk-navbar-right,[class*=uk-navbar-center]{gap:30px}.uk-navbar-center-right{left:calc(100% + 30px)}.uk-navbar-center-left{right:calc(100% + 30px)}}@media (min-width:960px){.uk-navbar-nav{gap:30px}}.uk-subnav{display:flex;flex-wrap:wrap;align-items:center;margin-right:-20px;padding:0;list-style:none}.uk-subnav>*{flex:none;padding-right:20px;position:relative}.uk-subnav>*>:first-child{display:flex;align-items:center;column-gap:.25em;color:#999;font-size:.875rem;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color}.uk-subnav>*>a:hover{color:#666;text-decoration:none}.uk-subnav>.uk-active>a{color:#333}.uk-subnav-divider{margin-right:-41px}.uk-subnav-divider>*{display:flex;align-items:center}.uk-subnav-divider>::before{content:"";height:1.5em;margin-right:0;margin-left:20px;border-right:1px solid transparent}.uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{border-right-color:#e5e5e5}.uk-subnav-pill{margin-right:-20px}.uk-subnav-pill>*{padding-right:20px}.uk-subnav-pill>*>:first-child{padding:5px 10px;background:0 0;color:#999}.uk-subnav-pill>*>a:hover{background-color:#f8f8f8;color:#666}.uk-subnav-pill>*>a:active{background-color:#f8f8f8;color:#666}.uk-subnav-pill>.uk-active>a{background-color:#1e87f0;color:#fff}.uk-subnav>.uk-disabled>a{color:#999}.uk-breadcrumb{padding:0;list-style:none;font-size:0}.uk-breadcrumb>*{display:contents}.uk-breadcrumb>*>*{font-size:.875rem;color:#999}.uk-breadcrumb>*>:hover{color:#666;text-decoration:none}.uk-breadcrumb>:last-child>a:not([href]),.uk-breadcrumb>:last-child>span{color:#666}.uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before{content:"/";display:inline-block;margin:0 20px;font-size:.875rem;color:#999}.uk-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-right:0;padding:0;list-style:none}.uk-pagination>*{flex:none;padding-right:0;position:relative}.uk-pagination>*>*{display:flex;align-items:center;column-gap:.25em;padding:5px 10px;color:#999;transition:color .1s ease-in-out}.uk-pagination>*>:hover{color:#666;text-decoration:none}.uk-pagination>.uk-active>*{color:#666}.uk-pagination>.uk-disabled>*{color:#999}.uk-tab{display:flex;flex-wrap:wrap;margin-right:-20px;padding:0;list-style:none;position:relative}.uk-tab::before{content:"";position:absolute;bottom:0;right:20px;left:0;border-bottom:1px solid #e5e5e5}.uk-tab>*{flex:none;padding-right:20px;position:relative}.uk-tab>*>a{display:flex;align-items:center;column-gap:.25em;justify-content:center;padding:5px 10px;color:#999;border-bottom:1px solid transparent;font-size:.875rem;text-transform:uppercase;transition:color .1s ease-in-out}.uk-tab>*>a:hover{color:#666;text-decoration:none}.uk-tab>.uk-active>a{color:#333;border-color:#1e87f0}.uk-tab>.uk-disabled>a{color:#999}.uk-tab-bottom::before{top:0;bottom:auto}.uk-tab-bottom>*>a{border-top:1px solid transparent;border-bottom:none}.uk-tab-left,.uk-tab-right{flex-direction:column;margin-right:0}.uk-tab-left>*,.uk-tab-right>*{padding-right:0}.uk-tab-right::before{top:0;bottom:0;right:auto;left:0;border-right:1px solid #e5e5e5;border-bottom:none}.uk-tab-left::before{top:0;bottom:0;right:0;left:auto;border-right:1px solid #e5e5e5;border-bottom:none}.uk-tab-right>*>a{justify-content:right;border-left:1px solid transparent;border-bottom:none}.uk-tab-left>*>a{justify-content:right;border-right:1px solid transparent;border-bottom:none}.uk-tab .uk-dropdown{margin-right:30px}.uk-slidenav{padding:5px 10px;color:rgba(102,102,102,.5);transition:color .1s ease-in-out}.uk-slidenav:hover{color:rgba(102,102,102,.9)}.uk-slidenav:active{color:rgba(102,102,102,.5)}.uk-slidenav-large{padding:10px 10px}.uk-slidenav-container{display:flex}.uk-dotnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-right:-12px}.uk-dotnav>*{flex:none;padding-right:12px}.uk-dotnav>*>*{display:block;box-sizing:border-box;width:10px;height:10px;border-radius:50%;background:0 0;text-indent:100%;overflow:hidden;white-space:nowrap;border:1px solid rgba(102,102,102,.4);transition:.2s ease-in-out;transition-property:background-color,border-color}.uk-dotnav>*>:hover{background-color:rgba(102,102,102,.6);border-color:transparent}.uk-dotnav>*>:active{background-color:rgba(102,102,102,.2);border-color:transparent}.uk-dotnav>.uk-active>*{background-color:rgba(102,102,102,.6);border-color:transparent}.uk-dotnav-vertical{flex-direction:column;margin-right:0;margin-top:-12px}.uk-dotnav-vertical>*{padding-right:0;padding-top:12px}.uk-dropdown{--uk-position-offset:10px;--uk-position-viewport-offset:15px;--uk-inverse:dark;width:auto;min-width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,.15)}.uk-dropdown>:last-child{margin-bottom:0}.uk-dropdown :focus-visible{outline-color:#333!important}.uk-dropdown-large{padding:40px}.uk-dropdown-dropbar{--uk-position-offset:10px;width:auto;background:0 0;padding:5px 0 25px 0;--uk-position-viewport-offset:15px;box-shadow:none}@media (min-width:640px){.uk-dropdown-dropbar{--uk-position-viewport-offset:30px}}@media (min-width:960px){.uk-dropdown-dropbar{--uk-position-viewport-offset:40px}}.uk-dropdown-dropbar-large{padding-top:40px;padding-bottom:40px}.uk-dropdown-nav{font-size:.875rem}.uk-dropdown-nav>li>a{color:#999}.uk-dropdown-nav>li.uk-active>a,.uk-dropdown-nav>li>a:hover{color:#666}.uk-dropdown-nav .uk-nav-subtitle{font-size:12px}.uk-dropdown-nav .uk-nav-header{color:#333}.uk-dropdown-nav .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-dropdown-nav .uk-nav-sub a{color:#999}.uk-dropdown-nav .uk-nav-sub a:hover,.uk-dropdown-nav .uk-nav-sub li.uk-active>a{color:#666}.uk-lightbox{--uk-inverse:light;display:none;position:fixed;top:0;left:0;bottom:0;right:0;z-index:1010;background:#000;opacity:0;transition:opacity .15s linear;touch-action:pinch-zoom}.uk-lightbox.uk-open{display:block;opacity:1}.uk-lightbox :focus-visible{outline-color:rgba(255,255,255,.7)}.uk-lightbox-page{overflow:hidden}.uk-lightbox-items{margin:0;padding:0;list-style:none}.uk-lightbox-items>*{position:absolute;top:0;left:0;bottom:0;right:0;display:none;justify-content:center;align-items:flex-start;will-change:transform,opacity;overflow:auto}.uk-lightbox-items>.uk-active{display:flex}.uk-lightbox-items-fit>*{align-items:center}.uk-lightbox-items-fit>*>*{max-width:100vw;max-height:100vh}.uk-lightbox-items-fit>*>:not(iframe){width:auto;height:auto}.uk-lightbox-items.uk-lightbox-items-fit .uk-lightbox-zoom:hover{cursor:zoom-in}.uk-lightbox-items:not(.uk-lightbox-items-fit) .uk-lightbox-zoom:hover{cursor:zoom-out}.uk-lightbox-thumbnav-vertical :where(img,video){max-width:100px}.uk-lightbox-thumbnav:not(.uk-lightbox-thumbnav-vertical) :where(img,video){max-height:100px}.uk-lightbox-dotnav:empty,.uk-lightbox-thumbnav:empty{display:none}.uk-lightbox-caption:empty{display:none}.uk-lightbox-caption{padding:10px 10px;background:rgba(0,0,0,.3);color:rgba(255,255,255,.7)}.uk-lightbox-caption>*{color:rgba(255,255,255,.7)}.uk-lightbox-counter:empty{display:none}.uk-lightbox-iframe{width:80%;height:80%}[class*=uk-animation-]{animation:.5s ease-out both}.uk-animation-fade{animation-name:uk-fade;animation-duration:.8s;animation-timing-function:linear}.uk-animation-scale-up{animation-name:uk-fade,uk-scale-up}.uk-animation-scale-down{animation-name:uk-fade,uk-scale-down}.uk-animation-slide-top{animation-name:uk-fade,uk-slide-top}.uk-animation-slide-bottom{animation-name:uk-fade,uk-slide-bottom}.uk-animation-slide-right{animation-name:uk-fade,uk-slide-left}.uk-animation-slide-left{animation-name:uk-fade,uk-slide-right}.uk-animation-slide-top-small{animation-name:uk-fade,uk-slide-top-small}.uk-animation-slide-bottom-small{animation-name:uk-fade,uk-slide-bottom-small}.uk-animation-slide-right-small{animation-name:uk-fade,uk-slide-left-small}.uk-animation-slide-left-small{animation-name:uk-fade,uk-slide-right-small}.uk-animation-slide-top-medium{animation-name:uk-fade,uk-slide-top-medium}.uk-animation-slide-bottom-medium{animation-name:uk-fade,uk-slide-bottom-medium}.uk-animation-slide-right-medium{animation-name:uk-fade,uk-slide-left-medium}.uk-animation-slide-left-medium{animation-name:uk-fade,uk-slide-right-medium}.uk-animation-kenburns{animation-name:uk-kenburns;animation-duration:15s}.uk-animation-shake{animation-name:uk-shake}.uk-animation-stroke{animation-name:uk-stroke;animation-duration:2s;stroke-dasharray:var(--uk-animation-stroke)}.uk-animation-reverse{animation-direction:reverse;animation-timing-function:ease-in}.uk-animation-fast{animation-duration:.1s}.uk-animation-toggle:not(:hover):not(:focus) [class*=uk-animation-]{animation-name:none}@keyframes uk-fade{0%{opacity:0}100%{opacity:1}}@keyframes uk-scale-up{0%{transform:scale(.9)}100%{transform:scale(1)}}@keyframes uk-scale-down{0%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes uk-slide-top{0%{transform:translateY(-100%)}100%{transform:translateY(0)}}@keyframes uk-slide-bottom{0%{transform:translateY(100%)}100%{transform:translateY(0)}}@keyframes uk-slide-left{0%{transform:translateX(100%)}100%{transform:translateX(0)}}@keyframes uk-slide-right{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes uk-slide-top-small{0%{transform:translateY(-10px)}100%{transform:translateY(0)}}@keyframes uk-slide-bottom-small{0%{transform:translateY(10px)}100%{transform:translateY(0)}}@keyframes uk-slide-left-small{0%{transform:translateX(10px)}100%{transform:translateX(0)}}@keyframes uk-slide-right-small{0%{transform:translateX(-10px)}100%{transform:translateX(0)}}@keyframes uk-slide-top-medium{0%{transform:translateY(-50px)}100%{transform:translateY(0)}}@keyframes uk-slide-bottom-medium{0%{transform:translateY(50px)}100%{transform:translateY(0)}}@keyframes uk-slide-left-medium{0%{transform:translateX(50px)}100%{transform:translateX(0)}}@keyframes uk-slide-right-medium{0%{transform:translateX(-50px)}100%{transform:translateX(0)}}@keyframes uk-kenburns{0%{transform:scale(1)}100%{transform:scale(1.2)}}@keyframes uk-shake{0%,100%{transform:translateX(0)}10%{transform:translateX(9px)}20%{transform:translateX(-8px)}30%{transform:translateX(7px)}40%{transform:translateX(-6px)}50%{transform:translateX(5px)}60%{transform:translateX(-4px)}70%{transform:translateX(3px)}80%{transform:translateX(-2px)}90%{transform:translateX(1px)}}@keyframes uk-stroke{0%{stroke-dashoffset:var(--uk-animation-stroke)}100%{stroke-dashoffset:0}}[class*=uk-child-width]>*{box-sizing:border-box;width:100%}.uk-child-width-1-2>*{width:50%}.uk-child-width-1-3>*{width:calc(100% / 3)}.uk-child-width-1-4>*{width:25%}.uk-child-width-1-5>*{width:20%}.uk-child-width-1-6>*{width:calc(100% / 6)}.uk-child-width-auto>*{width:auto}.uk-child-width-expand>:not([class*=uk-width]){flex:1;min-width:1px}@media (min-width:640px){.uk-child-width-1-1\@s>*{width:100%}.uk-child-width-1-2\@s>*{width:50%}.uk-child-width-1-3\@s>*{width:calc(100% / 3)}.uk-child-width-1-4\@s>*{width:25%}.uk-child-width-1-5\@s>*{width:20%}.uk-child-width-1-6\@s>*{width:calc(100% / 6)}.uk-child-width-auto\@s>*{width:auto}.uk-child-width-expand\@s>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@s>:not([class*=uk-width]),.uk-child-width-1-2\@s>:not([class*=uk-width]),.uk-child-width-1-3\@s>:not([class*=uk-width]),.uk-child-width-1-4\@s>:not([class*=uk-width]),.uk-child-width-1-5\@s>:not([class*=uk-width]),.uk-child-width-1-6\@s>:not([class*=uk-width]),.uk-child-width-auto\@s>:not([class*=uk-width]){flex:initial}}@media (min-width:960px){.uk-child-width-1-1\@m>*{width:100%}.uk-child-width-1-2\@m>*{width:50%}.uk-child-width-1-3\@m>*{width:calc(100% / 3)}.uk-child-width-1-4\@m>*{width:25%}.uk-child-width-1-5\@m>*{width:20%}.uk-child-width-1-6\@m>*{width:calc(100% / 6)}.uk-child-width-auto\@m>*{width:auto}.uk-child-width-expand\@m>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@m>:not([class*=uk-width]),.uk-child-width-1-2\@m>:not([class*=uk-width]),.uk-child-width-1-3\@m>:not([class*=uk-width]),.uk-child-width-1-4\@m>:not([class*=uk-width]),.uk-child-width-1-5\@m>:not([class*=uk-width]),.uk-child-width-1-6\@m>:not([class*=uk-width]),.uk-child-width-auto\@m>:not([class*=uk-width]){flex:initial}}@media (min-width:1200px){.uk-child-width-1-1\@l>*{width:100%}.uk-child-width-1-2\@l>*{width:50%}.uk-child-width-1-3\@l>*{width:calc(100% / 3)}.uk-child-width-1-4\@l>*{width:25%}.uk-child-width-1-5\@l>*{width:20%}.uk-child-width-1-6\@l>*{width:calc(100% / 6)}.uk-child-width-auto\@l>*{width:auto}.uk-child-width-expand\@l>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@l>:not([class*=uk-width]),.uk-child-width-1-2\@l>:not([class*=uk-width]),.uk-child-width-1-3\@l>:not([class*=uk-width]),.uk-child-width-1-4\@l>:not([class*=uk-width]),.uk-child-width-1-5\@l>:not([class*=uk-width]),.uk-child-width-1-6\@l>:not([class*=uk-width]),.uk-child-width-auto\@l>:not([class*=uk-width]){flex:initial}}@media (min-width:1600px){.uk-child-width-1-1\@xl>*{width:100%}.uk-child-width-1-2\@xl>*{width:50%}.uk-child-width-1-3\@xl>*{width:calc(100% / 3)}.uk-child-width-1-4\@xl>*{width:25%}.uk-child-width-1-5\@xl>*{width:20%}.uk-child-width-1-6\@xl>*{width:calc(100% / 6)}.uk-child-width-auto\@xl>*{width:auto}.uk-child-width-expand\@xl>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@xl>:not([class*=uk-width]),.uk-child-width-1-2\@xl>:not([class*=uk-width]),.uk-child-width-1-3\@xl>:not([class*=uk-width]),.uk-child-width-1-4\@xl>:not([class*=uk-width]),.uk-child-width-1-5\@xl>:not([class*=uk-width]),.uk-child-width-1-6\@xl>:not([class*=uk-width]),.uk-child-width-auto\@xl>:not([class*=uk-width]){flex:initial}}[class*=uk-width]{box-sizing:border-box;width:100%;max-width:100%}.uk-width-1-2{width:50%}.uk-width-1-3{width:calc(100% / 3)}.uk-width-2-3{width:calc(200% / 3)}.uk-width-1-4{width:25%}.uk-width-3-4{width:75%}.uk-width-1-5{width:20%}.uk-width-2-5{width:40%}.uk-width-3-5{width:60%}.uk-width-4-5{width:80%}.uk-width-1-6{width:calc(100% / 6)}.uk-width-5-6{width:calc(500% / 6)}.uk-width-small{width:150px}.uk-width-medium{width:300px}.uk-width-large{width:450px}.uk-width-xlarge{width:600px}.uk-width-2xlarge{width:750px}.uk-width-auto{width:auto}.uk-width-expand{flex:1;min-width:1px}@media (min-width:640px){.uk-width-1-1\@s{width:100%}.uk-width-1-2\@s{width:50%}.uk-width-1-3\@s{width:calc(100% / 3)}.uk-width-2-3\@s{width:calc(200% / 3)}.uk-width-1-4\@s{width:25%}.uk-width-3-4\@s{width:75%}.uk-width-1-5\@s{width:20%}.uk-width-2-5\@s{width:40%}.uk-width-3-5\@s{width:60%}.uk-width-4-5\@s{width:80%}.uk-width-1-6\@s{width:calc(100% / 6)}.uk-width-5-6\@s{width:calc(500% / 6)}.uk-width-small\@s{width:150px}.uk-width-medium\@s{width:300px}.uk-width-large\@s{width:450px}.uk-width-xlarge\@s{width:600px}.uk-width-2xlarge\@s{width:750px}.uk-width-auto\@s{width:auto}.uk-width-expand\@s{flex:1;min-width:1px}.uk-width-1-1\@s,.uk-width-1-2\@s,.uk-width-1-3\@s,.uk-width-1-4\@s,.uk-width-1-5\@s,.uk-width-1-6\@s,.uk-width-2-3\@s,.uk-width-2-5\@s,.uk-width-2xlarge\@s,.uk-width-3-4\@s,.uk-width-3-5\@s,.uk-width-4-5\@s,.uk-width-5-6\@s,.uk-width-auto\@s,.uk-width-large\@s,.uk-width-medium\@s,.uk-width-small\@s,.uk-width-xlarge\@s{flex:initial}}@media (min-width:960px){.uk-width-1-1\@m{width:100%}.uk-width-1-2\@m{width:50%}.uk-width-1-3\@m{width:calc(100% / 3)}.uk-width-2-3\@m{width:calc(200% / 3)}.uk-width-1-4\@m{width:25%}.uk-width-3-4\@m{width:75%}.uk-width-1-5\@m{width:20%}.uk-width-2-5\@m{width:40%}.uk-width-3-5\@m{width:60%}.uk-width-4-5\@m{width:80%}.uk-width-1-6\@m{width:calc(100% / 6)}.uk-width-5-6\@m{width:calc(500% / 6)}.uk-width-small\@m{width:150px}.uk-width-medium\@m{width:300px}.uk-width-large\@m{width:450px}.uk-width-xlarge\@m{width:600px}.uk-width-2xlarge\@m{width:750px}.uk-width-auto\@m{width:auto}.uk-width-expand\@m{flex:1;min-width:1px}.uk-width-1-1\@m,.uk-width-1-2\@m,.uk-width-1-3\@m,.uk-width-1-4\@m,.uk-width-1-5\@m,.uk-width-1-6\@m,.uk-width-2-3\@m,.uk-width-2-5\@m,.uk-width-2xlarge\@m,.uk-width-3-4\@m,.uk-width-3-5\@m,.uk-width-4-5\@m,.uk-width-5-6\@m,.uk-width-auto\@m,.uk-width-large\@m,.uk-width-medium\@m,.uk-width-small\@m,.uk-width-xlarge\@m{flex:initial}}@media (min-width:1200px){.uk-width-1-1\@l{width:100%}.uk-width-1-2\@l{width:50%}.uk-width-1-3\@l{width:calc(100% / 3)}.uk-width-2-3\@l{width:calc(200% / 3)}.uk-width-1-4\@l{width:25%}.uk-width-3-4\@l{width:75%}.uk-width-1-5\@l{width:20%}.uk-width-2-5\@l{width:40%}.uk-width-3-5\@l{width:60%}.uk-width-4-5\@l{width:80%}.uk-width-1-6\@l{width:calc(100% / 6)}.uk-width-5-6\@l{width:calc(500% / 6)}.uk-width-small\@l{width:150px}.uk-width-medium\@l{width:300px}.uk-width-large\@l{width:450px}.uk-width-xlarge\@l{width:600px}.uk-width-2xlarge\@l{width:750px}.uk-width-auto\@l{width:auto}.uk-width-expand\@l{flex:1;min-width:1px}.uk-width-1-1\@l,.uk-width-1-2\@l,.uk-width-1-3\@l,.uk-width-1-4\@l,.uk-width-1-5\@l,.uk-width-1-6\@l,.uk-width-2-3\@l,.uk-width-2-5\@l,.uk-width-2xlarge\@l,.uk-width-3-4\@l,.uk-width-3-5\@l,.uk-width-4-5\@l,.uk-width-5-6\@l,.uk-width-auto\@l,.uk-width-large\@l,.uk-width-medium\@l,.uk-width-small\@l,.uk-width-xlarge\@l{flex:initial}}@media (min-width:1600px){.uk-width-1-1\@xl{width:100%}.uk-width-1-2\@xl{width:50%}.uk-width-1-3\@xl{width:calc(100% / 3)}.uk-width-2-3\@xl{width:calc(200% / 3)}.uk-width-1-4\@xl{width:25%}.uk-width-3-4\@xl{width:75%}.uk-width-1-5\@xl{width:20%}.uk-width-2-5\@xl{width:40%}.uk-width-3-5\@xl{width:60%}.uk-width-4-5\@xl{width:80%}.uk-width-1-6\@xl{width:calc(100% / 6)}.uk-width-5-6\@xl{width:calc(500% / 6)}.uk-width-small\@xl{width:150px}.uk-width-medium\@xl{width:300px}.uk-width-large\@xl{width:450px}.uk-width-xlarge\@xl{width:600px}.uk-width-2xlarge\@xl{width:750px}.uk-width-auto\@xl{width:auto}.uk-width-expand\@xl{flex:1;min-width:1px}.uk-width-1-1\@xl,.uk-width-1-2\@xl,.uk-width-1-3\@xl,.uk-width-1-4\@xl,.uk-width-1-5\@xl,.uk-width-1-6\@xl,.uk-width-2-3\@xl,.uk-width-2-5\@xl,.uk-width-2xlarge\@xl,.uk-width-3-4\@xl,.uk-width-3-5\@xl,.uk-width-4-5\@xl,.uk-width-5-6\@xl,.uk-width-auto\@xl,.uk-width-large\@xl,.uk-width-medium\@xl,.uk-width-small\@xl,.uk-width-xlarge\@xl{flex:initial}}.uk-width-max-content{width:max-content}.uk-width-min-content{width:min-content}[class*=uk-height]{box-sizing:border-box}.uk-height-1-1{height:100%}.uk-height-viewport{min-height:100vh}.uk-height-viewport-2{min-height:200vh}.uk-height-viewport-3{min-height:300vh}.uk-height-viewport-4{min-height:400vh}.uk-height-small{height:150px}.uk-height-medium{height:300px}.uk-height-large{height:450px}.uk-height-max-small{max-height:150px}.uk-height-max-medium{max-height:300px}.uk-height-max-large{max-height:450px}.uk-text-lead{font-size:1.5rem;line-height:1.5;color:#333}.uk-text-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-text-meta>a{color:#999}.uk-text-meta>a:hover{color:#666;text-decoration:none}.uk-text-small{font-size:.875rem;line-height:1.5}.uk-text-large{font-size:1.5rem;line-height:1.5}.uk-text-default{font-size:16px;line-height:1.5}.uk-text-light{font-weight:300}.uk-text-normal{font-weight:400}.uk-text-bold{font-weight:700}.uk-text-lighter{font-weight:lighter}.uk-text-bolder{font-weight:bolder}.uk-text-italic{font-style:italic}.uk-text-capitalize{text-transform:capitalize!important}.uk-text-uppercase{text-transform:uppercase!important}.uk-text-lowercase{text-transform:lowercase!important}.uk-text-decoration-none{text-decoration:none!important}.uk-text-muted{color:#999!important}.uk-text-emphasis{color:#333!important}.uk-text-primary{color:#1e87f0!important}.uk-text-secondary{color:#222!important}.uk-text-success{color:#32d296!important}.uk-text-warning{color:#faa05a!important}.uk-text-danger{color:#f0506e!important}.uk-text-background{-webkit-background-clip:text;color:transparent!important;display:inline-block;background-color:#1e87f0;background-image:linear-gradient(-90deg,#1e87f0 0,#411ef0 100%)}.uk-text-right{text-align:right!important}.uk-text-left{text-align:left!important}.uk-text-center{text-align:center!important}.uk-text-justify{text-align:justify!important}@media (min-width:640px){.uk-text-right\@s{text-align:right!important}.uk-text-left\@s{text-align:left!important}.uk-text-center\@s{text-align:center!important}}@media (min-width:960px){.uk-text-right\@m{text-align:right!important}.uk-text-left\@m{text-align:left!important}.uk-text-center\@m{text-align:center!important}}@media (min-width:1200px){.uk-text-right\@l{text-align:right!important}.uk-text-left\@l{text-align:left!important}.uk-text-center\@l{text-align:center!important}}@media (min-width:1600px){.uk-text-right\@xl{text-align:right!important}.uk-text-left\@xl{text-align:left!important}.uk-text-center\@xl{text-align:center!important}}.uk-text-top{vertical-align:top!important}.uk-text-middle{vertical-align:middle!important}.uk-text-bottom{vertical-align:bottom!important}.uk-text-baseline{vertical-align:baseline!important}.uk-text-nowrap{white-space:nowrap}.uk-text-truncate{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}td.uk-text-truncate,th.uk-text-truncate{max-width:0}.uk-text-break{overflow-wrap:break-word}td.uk-text-break,th.uk-text-break{word-break:break-word}.uk-text-stroke{-webkit-text-stroke:calc(1.4px + 0.002em);-webkit-text-fill-color:transparent}[class*=uk-column-]{column-gap:30px}@media (min-width:1200px){[class*=uk-column-]{column-gap:40px}}[class*=uk-column-] img{transform:translate3d(0,0,0)}.uk-column-divider{column-rule:1px solid #e5e5e5;column-gap:60px}@media (min-width:1200px){.uk-column-divider{column-gap:80px}}.uk-column-1-2{column-count:2}.uk-column-1-3{column-count:3}.uk-column-1-4{column-count:4}.uk-column-1-5{column-count:5}.uk-column-1-6{column-count:6}@media (min-width:640px){.uk-column-1-2\@s{column-count:2}.uk-column-1-3\@s{column-count:3}.uk-column-1-4\@s{column-count:4}.uk-column-1-5\@s{column-count:5}.uk-column-1-6\@s{column-count:6}}@media (min-width:960px){.uk-column-1-2\@m{column-count:2}.uk-column-1-3\@m{column-count:3}.uk-column-1-4\@m{column-count:4}.uk-column-1-5\@m{column-count:5}.uk-column-1-6\@m{column-count:6}}@media (min-width:1200px){.uk-column-1-2\@l{column-count:2}.uk-column-1-3\@l{column-count:3}.uk-column-1-4\@l{column-count:4}.uk-column-1-5\@l{column-count:5}.uk-column-1-6\@l{column-count:6}}@media (min-width:1600px){.uk-column-1-2\@xl{column-count:2}.uk-column-1-3\@xl{column-count:3}.uk-column-1-4\@xl{column-count:4}.uk-column-1-5\@xl{column-count:5}.uk-column-1-6\@xl{column-count:6}}.uk-column-span{column-span:all}[data-uk-cover]:where(canvas,iframe,svg),[uk-cover]:where(canvas,iframe,svg){max-width:none;position:absolute;right:50%;top:50%;--uk-position-translate-x:50%;--uk-position-translate-y:-50%;transform:translate(var(--uk-position-translate-x),var(--uk-position-translate-y))}iframe[data-uk-cover],iframe[uk-cover]{pointer-events:none}[data-uk-cover]:where(img,video),[uk-cover]:where(img,video){position:absolute;top:0;right:0;width:100%;height:100%;box-sizing:border-box;object-fit:cover;object-position:center}.uk-cover-container{overflow:hidden;position:relative}.uk-background-default{background-color:#fff}.uk-background-muted{background-color:#f8f8f8}.uk-background-primary{background-color:#1e87f0}.uk-background-secondary{background-color:#222}.uk-background-contain,.uk-background-cover,.uk-background-height-1-1,.uk-background-width-1-1{background-position:50% 50%;background-repeat:no-repeat}.uk-background-cover{background-size:cover}.uk-background-contain{background-size:contain}.uk-background-width-1-1{background-size:100%}.uk-background-height-1-1{background-size:auto 100%}.uk-background-top-right{background-position:100% 0}.uk-background-top-center{background-position:50% 0}.uk-background-top-left{background-position:0 0}.uk-background-center-right{background-position:100% 50%}.uk-background-center-center{background-position:50% 50%}.uk-background-center-left{background-position:0 50%}.uk-background-bottom-right{background-position:100% 100%}.uk-background-bottom-center{background-position:50% 100%}.uk-background-bottom-left{background-position:0 100%}.uk-background-norepeat{background-repeat:no-repeat}.uk-background-fixed{background-attachment:fixed}@media (pointer:coarse){.uk-background-fixed{background-attachment:scroll}}@media (max-width:639px){.uk-background-image\@s{background-image:none!important}}@media (max-width:959px){.uk-background-image\@m{background-image:none!important}}@media (max-width:1199px){.uk-background-image\@l{background-image:none!important}}@media (max-width:1599px){.uk-background-image\@xl{background-image:none!important}}.uk-background-blend-multiply{background-blend-mode:multiply}.uk-background-blend-screen{background-blend-mode:screen}.uk-background-blend-overlay{background-blend-mode:overlay}.uk-background-blend-darken{background-blend-mode:darken}.uk-background-blend-lighten{background-blend-mode:lighten}.uk-background-blend-color-dodge{background-blend-mode:color-dodge}.uk-background-blend-color-burn{background-blend-mode:color-burn}.uk-background-blend-hard-light{background-blend-mode:hard-light}.uk-background-blend-soft-light{background-blend-mode:soft-light}.uk-background-blend-difference{background-blend-mode:difference}.uk-background-blend-exclusion{background-blend-mode:exclusion}.uk-background-blend-hue{background-blend-mode:hue}.uk-background-blend-saturation{background-blend-mode:saturation}.uk-background-blend-color{background-blend-mode:color}.uk-background-blend-luminosity{background-blend-mode:luminosity}[class*=uk-align]{display:block;margin-bottom:30px}*+[class*=uk-align]{margin-top:30px}.uk-align-center{margin-right:auto;margin-left:auto}.uk-align-right{margin-top:0;margin-left:30px;float:right}.uk-align-left{margin-top:0;margin-right:30px;float:left}@media (min-width:640px){.uk-align-right\@s{margin-top:0;margin-left:30px;float:right}.uk-align-left\@s{margin-top:0;margin-right:30px;float:left}}@media (min-width:960px){.uk-align-right\@m{margin-top:0;margin-left:30px;float:right}.uk-align-left\@m{margin-top:0;margin-right:30px;float:left}}@media (min-width:1200px){.uk-align-right\@l{margin-top:0;float:right}.uk-align-left\@l{margin-top:0;float:left}.uk-align-right,.uk-align-right\@l,.uk-align-right\@m,.uk-align-right\@s{margin-left:40px}.uk-align-left,.uk-align-left\@l,.uk-align-left\@m,.uk-align-left\@s{margin-right:40px}}@media (min-width:1600px){.uk-align-right\@xl{margin-top:0;margin-left:40px;float:right}.uk-align-left\@xl{margin-top:0;margin-right:40px;float:left}}.uk-svg,.uk-svg:not(.uk-preserve) [fill*="#"]:not(.uk-preserve){fill:currentcolor}.uk-svg:not(.uk-preserve) [stroke*="#"]:not(.uk-preserve){stroke:currentcolor}.uk-svg{transform:translate(0,0)}.uk-panel{display:flow-root;position:relative;box-sizing:border-box}.uk-panel>:last-child{margin-bottom:0}.uk-panel-scrollable{height:170px;padding:10px;border:1px solid #e5e5e5;overflow:auto;resize:both}.uk-clearfix::before{content:"";display:table-cell}.uk-clearfix::after{content:"";display:table;clear:both}.uk-float-right{float:right}.uk-float-left{float:left}[class*=uk-float-]{max-width:100%}.uk-overflow-hidden{overflow:hidden}.uk-overflow-auto{overflow:auto}.uk-overflow-auto>:last-child{margin-bottom:0}.uk-box-sizing-content{box-sizing:content-box}.uk-box-sizing-border{box-sizing:border-box}.uk-resize{resize:both}.uk-resize-horizontal{resize:horizontal}.uk-resize-vertical{resize:vertical}.uk-display-block{display:block!important}.uk-display-inline{display:inline!important}.uk-display-inline-block{display:inline-block!important}[class*=uk-inline]{display:inline-block;position:relative;max-width:100%;vertical-align:middle;-webkit-backface-visibility:hidden}.uk-inline-clip{overflow:hidden}.uk-preserve-width,.uk-preserve-width canvas,.uk-preserve-width img,.uk-preserve-width svg,.uk-preserve-width video{max-width:none}.uk-responsive-height,.uk-responsive-width{box-sizing:border-box}.uk-responsive-width{max-width:100%!important;height:auto}.uk-responsive-height{max-height:100%;width:auto;max-width:none}[data-uk-responsive],[uk-responsive]{max-width:100%}.uk-object-cover{object-fit:cover}.uk-object-contain{object-fit:contain}.uk-object-fill{object-fit:fill}.uk-object-none{object-fit:none}.uk-object-scale-down{object-fit:scale-down}.uk-object-top-right{object-position:100% 0}.uk-object-top-center{object-position:50% 0}.uk-object-top-left{object-position:0% 0}.uk-object-center-right{object-position:100% 50%}.uk-object-center-center{object-position:50% 50%}.uk-object-center-left{object-position:0% 50%}.uk-object-bottom-right{object-position:100% 100%}.uk-object-bottom-center{object-position:50% 100%}.uk-object-bottom-left{object-position:0% 100%}.uk-border-circle{border-radius:50%}.uk-border-pill{border-radius:500px}.uk-border-rounded{border-radius:5px}.uk-inline-clip[class*=uk-border-]{-webkit-transform:translateZ(0)}.uk-box-shadow-small{box-shadow:0 2px 8px rgba(0,0,0,.08)}.uk-box-shadow-medium{box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-box-shadow-large{box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-box-shadow-xlarge{box-shadow:0 28px 50px rgba(0,0,0,.16)}[class*=uk-box-shadow-hover]{transition:box-shadow .1s ease-in-out}.uk-box-shadow-hover-small:hover{box-shadow:0 2px 8px rgba(0,0,0,.08)}.uk-box-shadow-hover-medium:hover{box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-box-shadow-hover-large:hover{box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-box-shadow-hover-xlarge:hover{box-shadow:0 28px 50px rgba(0,0,0,.16)}@supports (filter:blur(0)){.uk-box-shadow-bottom{display:inline-block;position:relative;z-index:0;max-width:100%;vertical-align:middle}.uk-box-shadow-bottom::after{content:"";position:absolute;bottom:-30px;right:0;left:0;z-index:-1;height:30px;border-radius:100%;background:#444;filter:blur(20px);will-change:filter}}.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{display:block;margin-left:10px;float:right;font-size:4.5em;line-height:1;margin-bottom:-2px}@-moz-document url-prefix(){.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{margin-top:1.1%}}.uk-logo{font-size:1.5rem;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";color:#333;text-decoration:none}:where(.uk-logo){display:inline-block;vertical-align:middle}.uk-logo:hover{color:#333;text-decoration:none}.uk-logo :where(img,svg,video){display:block}.uk-logo-inverse{display:none}.uk-disabled{pointer-events:none}.uk-drag,.uk-drag *{cursor:move}.uk-drag iframe{pointer-events:none}.uk-dragover{box-shadow:0 0 20px rgba(100,100,100,.3)}.uk-blend-multiply{mix-blend-mode:multiply}.uk-blend-screen{mix-blend-mode:screen}.uk-blend-overlay{mix-blend-mode:overlay}.uk-blend-darken{mix-blend-mode:darken}.uk-blend-lighten{mix-blend-mode:lighten}.uk-blend-color-dodge{mix-blend-mode:color-dodge}.uk-blend-color-burn{mix-blend-mode:color-burn}.uk-blend-hard-light{mix-blend-mode:hard-light}.uk-blend-soft-light{mix-blend-mode:soft-light}.uk-blend-difference{mix-blend-mode:difference}.uk-blend-exclusion{mix-blend-mode:exclusion}.uk-blend-hue{mix-blend-mode:hue}.uk-blend-saturation{mix-blend-mode:saturation}.uk-blend-color{mix-blend-mode:color}.uk-blend-luminosity{mix-blend-mode:luminosity}.uk-transform-center{transform:translate(50%,-50%)}.uk-transform-origin-top-right{transform-origin:100% 0}.uk-transform-origin-top-center{transform-origin:50% 0}.uk-transform-origin-top-left{transform-origin:0% 0}.uk-transform-origin-center-right{transform-origin:100% 50%}.uk-transform-origin-center-left{transform-origin:0% 50%}.uk-transform-origin-bottom-right{transform-origin:100% 100%}.uk-transform-origin-bottom-center{transform-origin:50% 100%}.uk-transform-origin-bottom-left{transform-origin:0% 100%}.uk-flex{display:flex}.uk-flex-inline{display:inline-flex}.uk-flex-right{justify-content:flex-start}.uk-flex-center{justify-content:center}.uk-flex-left{justify-content:flex-end}.uk-flex-between{justify-content:space-between}.uk-flex-around{justify-content:space-around}@media (min-width:640px){.uk-flex-right\@s{justify-content:flex-start}.uk-flex-center\@s{justify-content:center}.uk-flex-left\@s{justify-content:flex-end}.uk-flex-between\@s{justify-content:space-between}.uk-flex-around\@s{justify-content:space-around}}@media (min-width:960px){.uk-flex-right\@m{justify-content:flex-start}.uk-flex-center\@m{justify-content:center}.uk-flex-left\@m{justify-content:flex-end}.uk-flex-between\@m{justify-content:space-between}.uk-flex-around\@m{justify-content:space-around}}@media (min-width:1200px){.uk-flex-right\@l{justify-content:flex-start}.uk-flex-center\@l{justify-content:center}.uk-flex-left\@l{justify-content:flex-end}.uk-flex-between\@l{justify-content:space-between}.uk-flex-around\@l{justify-content:space-around}}@media (min-width:1600px){.uk-flex-right\@xl{justify-content:flex-start}.uk-flex-center\@xl{justify-content:center}.uk-flex-left\@xl{justify-content:flex-end}.uk-flex-between\@xl{justify-content:space-between}.uk-flex-around\@xl{justify-content:space-around}}.uk-flex-stretch{align-items:stretch}.uk-flex-top{align-items:flex-start}.uk-flex-middle{align-items:center}.uk-flex-bottom{align-items:flex-end}@media (min-width:640px){.uk-flex-stretch\@s{align-items:stretch}.uk-flex-top\@s{align-items:flex-start}.uk-flex-middle\@s{align-items:center}.uk-flex-bottom\@s{align-items:flex-end}}@media (min-width:960px){.uk-flex-stretch\@m{align-items:stretch}.uk-flex-top\@m{align-items:flex-start}.uk-flex-middle\@m{align-items:center}.uk-flex-bottom\@m{align-items:flex-end}}@media (min-width:1200px){.uk-flex-stretch\@l{align-items:stretch}.uk-flex-top\@l{align-items:flex-start}.uk-flex-middle\@l{align-items:center}.uk-flex-bottom\@l{align-items:flex-end}}@media (min-width:1600px){.uk-flex-stretch\@xl{align-items:stretch}.uk-flex-top\@xl{align-items:flex-start}.uk-flex-middle\@xl{align-items:center}.uk-flex-bottom\@xl{align-items:flex-end}}.uk-flex-row{flex-direction:row}.uk-flex-row-reverse{flex-direction:row-reverse}.uk-flex-column{flex-direction:column}.uk-flex-column-reverse{flex-direction:column-reverse}@media (min-width:640px){.uk-flex-row\@s{flex-direction:row}.uk-flex-column\@s{flex-direction:column}}@media (min-width:960px){.uk-flex-row\@m{flex-direction:row}.uk-flex-column\@m{flex-direction:column}}@media (min-width:1200px){.uk-flex-row\@l{flex-direction:row}.uk-flex-column\@l{flex-direction:column}}@media (min-width:1600px){.uk-flex-row\@xl{flex-direction:row}.uk-flex-column\@xl{flex-direction:column}}.uk-flex-nowrap{flex-wrap:nowrap}.uk-flex-wrap{flex-wrap:wrap}.uk-flex-wrap-reverse{flex-wrap:wrap-reverse}.uk-flex-wrap-stretch{align-content:stretch}.uk-flex-wrap-top{align-content:flex-start}.uk-flex-wrap-middle{align-content:center}.uk-flex-wrap-bottom{align-content:flex-end}.uk-flex-wrap-between{align-content:space-between}.uk-flex-wrap-around{align-content:space-around}.uk-flex-first{order:-1}.uk-flex-last{order:99}@media (min-width:640px){.uk-flex-first\@s{order:-1}.uk-flex-last\@s{order:99}}@media (min-width:960px){.uk-flex-first\@m{order:-1}.uk-flex-last\@m{order:99}}@media (min-width:1200px){.uk-flex-first\@l{order:-1}.uk-flex-last\@l{order:99}}@media (min-width:1600px){.uk-flex-first\@xl{order:-1}.uk-flex-last\@xl{order:99}}.uk-flex-initial{flex:initial}.uk-flex-none{flex:none}.uk-flex-auto{flex:auto}.uk-flex-1{flex:1}@media (min-width:640px){.uk-flex-initial\@s{flex:initial}.uk-flex-none\@s{flex:none}.uk-flex-1\@s{flex:1}}@media (min-width:960px){.uk-flex-initial\@m{flex:initial}.uk-flex-none\@m{flex:none}.uk-flex-1\@m{flex:1}}@media (min-width:1200px){.uk-flex-initial\@l{flex:initial}.uk-flex-none\@l{flex:none}.uk-flex-1\@l{flex:1}}@media (min-width:1600px){.uk-flex-initial\@xl{flex:initial}.uk-flex-none\@xl{flex:none}.uk-flex-1\@xl{flex:1}}.uk-margin{margin-bottom:20px}*+.uk-margin{margin-top:20px!important}.uk-margin-top{margin-top:20px!important}.uk-margin-bottom{margin-bottom:20px!important}.uk-margin-right{margin-right:20px!important}.uk-margin-left{margin-left:20px!important}.uk-margin-xsmall{margin-bottom:5px}*+.uk-margin-xsmall{margin-top:5px!important}.uk-margin-xsmall-top{margin-top:5px!important}.uk-margin-xsmall-bottom{margin-bottom:5px!important}.uk-margin-xsmall-right{margin-right:5px!important}.uk-margin-xsmall-left{margin-left:5px!important}.uk-margin-small{margin-bottom:10px}*+.uk-margin-small{margin-top:10px!important}.uk-margin-small-top{margin-top:10px!important}.uk-margin-small-bottom{margin-bottom:10px!important}.uk-margin-small-right{margin-right:10px!important}.uk-margin-small-left{margin-left:10px!important}.uk-margin-medium{margin-bottom:40px}*+.uk-margin-medium{margin-top:40px!important}.uk-margin-medium-top{margin-top:40px!important}.uk-margin-medium-bottom{margin-bottom:40px!important}.uk-margin-medium-right{margin-right:40px!important}.uk-margin-medium-left{margin-left:40px!important}.uk-margin-large{margin-bottom:40px}*+.uk-margin-large{margin-top:40px!important}.uk-margin-large-top{margin-top:40px!important}.uk-margin-large-bottom{margin-bottom:40px!important}.uk-margin-large-right{margin-right:40px!important}.uk-margin-large-left{margin-left:40px!important}@media (min-width:1200px){.uk-margin-large{margin-bottom:70px}*+.uk-margin-large{margin-top:70px!important}.uk-margin-large-top{margin-top:70px!important}.uk-margin-large-bottom{margin-bottom:70px!important}.uk-margin-large-right{margin-right:70px!important}.uk-margin-large-left{margin-left:70px!important}}.uk-margin-xlarge{margin-bottom:70px}*+.uk-margin-xlarge{margin-top:70px!important}.uk-margin-xlarge-top{margin-top:70px!important}.uk-margin-xlarge-bottom{margin-bottom:70px!important}.uk-margin-xlarge-right{margin-right:70px!important}.uk-margin-xlarge-left{margin-left:70px!important}@media (min-width:1200px){.uk-margin-xlarge{margin-bottom:140px}*+.uk-margin-xlarge{margin-top:140px!important}.uk-margin-xlarge-top{margin-top:140px!important}.uk-margin-xlarge-bottom{margin-bottom:140px!important}.uk-margin-xlarge-right{margin-right:140px!important}.uk-margin-xlarge-left{margin-left:140px!important}}.uk-margin-auto{margin-right:auto!important;margin-left:auto!important}.uk-margin-auto-top{margin-top:auto!important}.uk-margin-auto-bottom{margin-bottom:auto!important}.uk-margin-auto-right{margin-right:auto!important}.uk-margin-auto-left{margin-left:auto!important}.uk-margin-auto-vertical{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:640px){.uk-margin-auto\@s{margin-right:auto!important;margin-left:auto!important}.uk-margin-auto-right\@s{margin-right:auto!important}.uk-margin-auto-left\@s{margin-left:auto!important}}@media (min-width:960px){.uk-margin-auto\@m{margin-right:auto!important;margin-left:auto!important}.uk-margin-auto-right\@m{margin-right:auto!important}.uk-margin-auto-left\@m{margin-left:auto!important}}@media (min-width:1200px){.uk-margin-auto\@l{margin-right:auto!important;margin-left:auto!important}.uk-margin-auto-right\@l{margin-right:auto!important}.uk-margin-auto-left\@l{margin-left:auto!important}}@media (min-width:1600px){.uk-margin-auto\@xl{margin-right:auto!important;margin-left:auto!important}.uk-margin-auto-right\@xl{margin-right:auto!important}.uk-margin-auto-left\@xl{margin-left:auto!important}}.uk-margin-remove{margin:0!important}.uk-margin-remove-top{margin-top:0!important}.uk-margin-remove-bottom{margin-bottom:0!important}.uk-margin-remove-right{margin-right:0!important}.uk-margin-remove-left{margin-left:0!important}.uk-margin-remove-vertical{margin-top:0!important;margin-bottom:0!important}.uk-margin-remove-adjacent+*,.uk-margin-remove-first-child>:first-child{margin-top:0!important}.uk-margin-remove-last-child>:last-child{margin-bottom:0!important}@media (min-width:640px){.uk-margin-remove-right\@s{margin-right:0!important}.uk-margin-remove-left\@s{margin-left:0!important}}@media (min-width:960px){.uk-margin-remove-right\@m{margin-right:0!important}.uk-margin-remove-left\@m{margin-left:0!important}}@media (min-width:1200px){.uk-margin-remove-right\@l{margin-right:0!important}.uk-margin-remove-left\@l{margin-left:0!important}}@media (min-width:1600px){.uk-margin-remove-right\@xl{margin-right:0!important}.uk-margin-remove-left\@xl{margin-left:0!important}}.uk-padding{padding:30px}@media (min-width:1200px){.uk-padding{padding:40px}}.uk-padding-small{padding:15px}.uk-padding-large{padding:40px}@media (min-width:1200px){.uk-padding-large{padding:70px}}.uk-padding-remove{padding:0!important}.uk-padding-remove-top{padding-top:0!important}.uk-padding-remove-bottom{padding-bottom:0!important}.uk-padding-remove-right{padding-right:0!important}.uk-padding-remove-left{padding-left:0!important}.uk-padding-remove-vertical{padding-top:0!important;padding-bottom:0!important}.uk-padding-remove-horizontal{padding-right:0!important;padding-left:0!important}:root{--uk-position-margin-offset:0px}[class*=uk-position-bottom],[class*=uk-position-center],[class*=uk-position-left],[class*=uk-position-right],[class*=uk-position-top]{position:absolute!important;max-width:calc(100% - (var(--uk-position-margin-offset) * 2));box-sizing:border-box}.uk-position-top{top:0;right:0;left:0}.uk-position-bottom{bottom:0;right:0;left:0}.uk-position-right{top:0;bottom:0;right:0}.uk-position-left{top:0;bottom:0;left:0}.uk-position-top-right{top:0;right:0}.uk-position-top-left{top:0;left:0}.uk-position-bottom-right{bottom:0;right:0}.uk-position-bottom-left{bottom:0;left:0}.uk-position-center{top:calc(50% - var(--uk-position-margin-offset));right:calc(50% - var(--uk-position-margin-offset));--uk-position-translate-x:50%;--uk-position-translate-y:-50%;transform:translate(var(--uk-position-translate-x),var(--uk-position-translate-y));width:max-content}.uk-position-center-vertical,[class*=uk-position-center-left],[class*=uk-position-center-right]{top:calc(50% - var(--uk-position-margin-offset));--uk-position-translate-y:-50%;transform:translate(0,var(--uk-position-translate-y))}.uk-position-center-right{right:0}.uk-position-center-left{left:0}.uk-position-center-vertical{right:0;left:0}.uk-position-center-right-out{left:100%;width:max-content}.uk-position-center-left-out{right:100%;width:max-content}.uk-position-bottom-center,.uk-position-center-horizontal,.uk-position-top-center{right:calc(50% - var(--uk-position-margin-offset));--uk-position-translate-x:50%;transform:translate(var(--uk-position-translate-x),0);width:max-content}.uk-position-top-center{top:0}.uk-position-bottom-center{bottom:0}.uk-position-center-horizontal{top:0;bottom:0}.uk-position-cover{position:absolute;top:0;bottom:0;right:0;left:0}.uk-position-small{margin:15px;--uk-position-margin-offset:15px}.uk-position-medium{margin:30px;--uk-position-margin-offset:30px}.uk-position-large{margin:30px;--uk-position-margin-offset:30px}@media (min-width:1200px){.uk-position-large{margin:50px;--uk-position-margin-offset:50px}}.uk-position-relative{position:relative!important}.uk-position-absolute{position:absolute!important}.uk-position-fixed{position:fixed!important}.uk-position-sticky{position:sticky!important}.uk-position-z-index{z-index:1}.uk-position-z-index-zero{z-index:0}.uk-position-z-index-negative{z-index:-1}.uk-position-z-index-high{z-index:990}:where(.uk-transition-fade),:where([class*=uk-transition-scale]),:where([class*=uk-transition-slide]){--uk-position-translate-x:0;--uk-position-translate-y:0}.uk-transition-fade,[class*=uk-transition-scale],[class*=uk-transition-slide]{--uk-translate-x:0;--uk-translate-y:0;--uk-scale-x:1;--uk-scale-y:1;transform:translate(var(--uk-position-translate-x),var(--uk-position-translate-y)) translate(var(--uk-translate-x),var(--uk-translate-y)) scale(var(--uk-scale-x),var(--uk-scale-y));transition:.3s ease-out;transition-property:opacity,transform,filter;opacity:0}.uk-transition-active.uk-active .uk-transition-fade,.uk-transition-toggle:focus .uk-transition-fade,.uk-transition-toggle:focus-within .uk-transition-fade,.uk-transition-toggle:hover .uk-transition-fade{opacity:1}[class*=uk-transition-scale]{-webkit-backface-visibility:hidden}.uk-transition-scale-up{--uk-scale-x:1;--uk-scale-y:1}.uk-transition-scale-down{--uk-scale-x:1.03;--uk-scale-y:1.03}.uk-transition-active.uk-active .uk-transition-scale-up,.uk-transition-toggle:focus .uk-transition-scale-up,.uk-transition-toggle:focus-within .uk-transition-scale-up,.uk-transition-toggle:hover .uk-transition-scale-up{--uk-scale-x:1.03;--uk-scale-y:1.03;opacity:1}.uk-transition-active.uk-active .uk-transition-scale-down,.uk-transition-toggle:focus .uk-transition-scale-down,.uk-transition-toggle:focus-within .uk-transition-scale-down,.uk-transition-toggle:hover .uk-transition-scale-down{--uk-scale-x:1;--uk-scale-y:1;opacity:1}.uk-transition-slide-top{--uk-translate-y:-100%}.uk-transition-slide-bottom{--uk-translate-y:100%}.uk-transition-slide-right{--uk-translate-x:-100%}.uk-transition-slide-left{--uk-translate-x:100%}.uk-transition-slide-top-small{--uk-translate-y:calc(-1 * 10px)}.uk-transition-slide-bottom-small{--uk-translate-y:10px}.uk-transition-slide-right-small{--uk-translate-x:calc(-1 * 10px)}.uk-transition-slide-left-small{--uk-translate-x:10px}.uk-transition-slide-top-medium{--uk-translate-y:calc(-1 * 50px)}.uk-transition-slide-bottom-medium{--uk-translate-y:50px}.uk-transition-slide-right-medium{--uk-translate-x:calc(-1 * 50px)}.uk-transition-slide-left-medium{--uk-translate-x:50px}.uk-transition-active.uk-active [class*=uk-transition-slide],.uk-transition-toggle:focus [class*=uk-transition-slide],.uk-transition-toggle:focus-within [class*=uk-transition-slide],.uk-transition-toggle:hover [class*=uk-transition-slide]{--uk-translate-x:0;--uk-translate-y:0;opacity:1}.uk-transition-opaque{opacity:1}.uk-transition-slow{transition-duration:.7s}.uk-transition-disable,.uk-transition-disable *{transition:none!important}.uk-hidden,.uk-hidden-empty:empty,[hidden]{display:none!important}@media (min-width:640px){.uk-hidden\@s{display:none!important}}@media (min-width:960px){.uk-hidden\@m{display:none!important}}@media (min-width:1200px){.uk-hidden\@l{display:none!important}}@media (min-width:1600px){.uk-hidden\@xl{display:none!important}}@media (max-width:639px){.uk-visible\@s{display:none!important}}@media (max-width:959px){.uk-visible\@m{display:none!important}}@media (max-width:1199px){.uk-visible\@l{display:none!important}}@media (max-width:1599px){.uk-visible\@xl{display:none!important}}.uk-invisible{visibility:hidden!important}.uk-hidden-visually:not(:focus):not(:active):not(:focus-within),.uk-visible-toggle:not(:hover):not(:focus) .uk-hidden-hover:not(:focus-visible):not(:has(:focus-visible)),.uk-visible-toggle:not(:hover):not(:focus) .uk-hidden-hover:not(:focus-within){position:absolute!important;width:0!important;height:0!important;padding:0!important;border:0!important;margin:0!important;overflow:hidden!important}.uk-visible-toggle:not(:hover):not(:focus) .uk-invisible-hover:not(:focus-within){opacity:0!important}@media (hover:none){.uk-hidden-touch{display:none!important}}@media (hover){.uk-hidden-notouch{display:none!important}}.uk-card-primary.uk-card-body,.uk-card-primary>:not([class*=uk-card-media]),.uk-card-secondary.uk-card-body,.uk-card-secondary>:not([class*=uk-card-media]),.uk-light,.uk-offcanvas-bar,.uk-overlay-primary,.uk-section-primary:not(.uk-preserve-color),.uk-section-secondary:not(.uk-preserve-color),.uk-tile-primary:not(.uk-preserve-color),.uk-tile-secondary:not(.uk-preserve-color){color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-link,.uk-card-primary.uk-card-body a,.uk-card-primary>:not([class*=uk-card-media]) .uk-link,.uk-card-primary>:not([class*=uk-card-media]) a,.uk-card-secondary.uk-card-body .uk-link,.uk-card-secondary.uk-card-body a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link,.uk-card-secondary>:not([class*=uk-card-media]) a,.uk-light .uk-link,.uk-light a,.uk-offcanvas-bar .uk-link,.uk-offcanvas-bar a,.uk-overlay-primary .uk-link,.uk-overlay-primary a,.uk-section-primary:not(.uk-preserve-color) .uk-link,.uk-section-primary:not(.uk-preserve-color) a,.uk-section-secondary:not(.uk-preserve-color) .uk-link,.uk-section-secondary:not(.uk-preserve-color) a,.uk-tile-primary:not(.uk-preserve-color) .uk-link,.uk-tile-primary:not(.uk-preserve-color) a,.uk-tile-secondary:not(.uk-preserve-color) .uk-link,.uk-tile-secondary:not(.uk-preserve-color) a{color:#fff}.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link,.uk-card-primary.uk-card-body .uk-link:hover,.uk-card-primary.uk-card-body a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-link:hover,.uk-card-primary>:not([class*=uk-card-media]) a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link,.uk-card-secondary.uk-card-body .uk-link:hover,.uk-card-secondary.uk-card-body a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) a:hover,.uk-light .uk-link-toggle:hover .uk-link,.uk-light .uk-link:hover,.uk-light a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link,.uk-offcanvas-bar .uk-link:hover,.uk-offcanvas-bar a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link,.uk-overlay-primary .uk-link:hover,.uk-overlay-primary a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-section-primary:not(.uk-preserve-color) .uk-link:hover,.uk-section-primary:not(.uk-preserve-color) a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-section-secondary:not(.uk-preserve-color) .uk-link:hover,.uk-section-secondary:not(.uk-preserve-color) a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-tile-primary:not(.uk-preserve-color) .uk-link:hover,.uk-tile-primary:not(.uk-preserve-color) a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-link:hover,.uk-tile-secondary:not(.uk-preserve-color) a:hover{color:#fff}.uk-card-primary.uk-card-body :not(pre)>code,.uk-card-primary.uk-card-body :not(pre)>kbd,.uk-card-primary.uk-card-body :not(pre)>samp,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>code,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>kbd,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>samp,.uk-card-secondary.uk-card-body :not(pre)>code,.uk-card-secondary.uk-card-body :not(pre)>kbd,.uk-card-secondary.uk-card-body :not(pre)>samp,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>code,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>kbd,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>samp,.uk-light :not(pre)>code,.uk-light :not(pre)>kbd,.uk-light :not(pre)>samp,.uk-offcanvas-bar :not(pre)>code,.uk-offcanvas-bar :not(pre)>kbd,.uk-offcanvas-bar :not(pre)>samp,.uk-overlay-primary :not(pre)>code,.uk-overlay-primary :not(pre)>kbd,.uk-overlay-primary :not(pre)>samp,.uk-section-primary:not(.uk-preserve-color) :not(pre)>code,.uk-section-primary:not(.uk-preserve-color) :not(pre)>kbd,.uk-section-primary:not(.uk-preserve-color) :not(pre)>samp,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>code,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>kbd,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>samp,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>code,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>kbd,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>samp,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>code,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>kbd,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>samp{color:rgba(255,255,255,.7);background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body em,.uk-card-primary>:not([class*=uk-card-media]) em,.uk-card-secondary.uk-card-body em,.uk-card-secondary>:not([class*=uk-card-media]) em,.uk-light em,.uk-offcanvas-bar em,.uk-overlay-primary em,.uk-section-primary:not(.uk-preserve-color) em,.uk-section-secondary:not(.uk-preserve-color) em,.uk-tile-primary:not(.uk-preserve-color) em,.uk-tile-secondary:not(.uk-preserve-color) em{color:#fff}.uk-card-primary.uk-card-body .uk-h1,.uk-card-primary.uk-card-body .uk-h2,.uk-card-primary.uk-card-body .uk-h3,.uk-card-primary.uk-card-body .uk-h4,.uk-card-primary.uk-card-body .uk-h5,.uk-card-primary.uk-card-body .uk-h6,.uk-card-primary.uk-card-body .uk-heading-2xlarge,.uk-card-primary.uk-card-body .uk-heading-3xlarge,.uk-card-primary.uk-card-body .uk-heading-large,.uk-card-primary.uk-card-body .uk-heading-medium,.uk-card-primary.uk-card-body .uk-heading-small,.uk-card-primary.uk-card-body .uk-heading-xlarge,.uk-card-primary.uk-card-body h1,.uk-card-primary.uk-card-body h2,.uk-card-primary.uk-card-body h3,.uk-card-primary.uk-card-body h4,.uk-card-primary.uk-card-body h5,.uk-card-primary.uk-card-body h6,.uk-card-primary>:not([class*=uk-card-media]) .uk-h1,.uk-card-primary>:not([class*=uk-card-media]) .uk-h2,.uk-card-primary>:not([class*=uk-card-media]) .uk-h3,.uk-card-primary>:not([class*=uk-card-media]) .uk-h4,.uk-card-primary>:not([class*=uk-card-media]) .uk-h5,.uk-card-primary>:not([class*=uk-card-media]) .uk-h6,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-2xlarge,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-3xlarge,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-large,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-medium,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-small,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-xlarge,.uk-card-primary>:not([class*=uk-card-media]) h1,.uk-card-primary>:not([class*=uk-card-media]) h2,.uk-card-primary>:not([class*=uk-card-media]) h3,.uk-card-primary>:not([class*=uk-card-media]) h4,.uk-card-primary>:not([class*=uk-card-media]) h5,.uk-card-primary>:not([class*=uk-card-media]) h6,.uk-card-secondary.uk-card-body .uk-h1,.uk-card-secondary.uk-card-body .uk-h2,.uk-card-secondary.uk-card-body .uk-h3,.uk-card-secondary.uk-card-body .uk-h4,.uk-card-secondary.uk-card-body .uk-h5,.uk-card-secondary.uk-card-body .uk-h6,.uk-card-secondary.uk-card-body .uk-heading-2xlarge,.uk-card-secondary.uk-card-body .uk-heading-3xlarge,.uk-card-secondary.uk-card-body .uk-heading-large,.uk-card-secondary.uk-card-body .uk-heading-medium,.uk-card-secondary.uk-card-body .uk-heading-small,.uk-card-secondary.uk-card-body .uk-heading-xlarge,.uk-card-secondary.uk-card-body h1,.uk-card-secondary.uk-card-body h2,.uk-card-secondary.uk-card-body h3,.uk-card-secondary.uk-card-body h4,.uk-card-secondary.uk-card-body h5,.uk-card-secondary.uk-card-body h6,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h1,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h2,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h3,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h4,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h5,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h6,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-2xlarge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-3xlarge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-large,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-medium,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-small,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-xlarge,.uk-card-secondary>:not([class*=uk-card-media]) h1,.uk-card-secondary>:not([class*=uk-card-media]) h2,.uk-card-secondary>:not([class*=uk-card-media]) h3,.uk-card-secondary>:not([class*=uk-card-media]) h4,.uk-card-secondary>:not([class*=uk-card-media]) h5,.uk-card-secondary>:not([class*=uk-card-media]) h6,.uk-light .uk-h1,.uk-light .uk-h2,.uk-light .uk-h3,.uk-light .uk-h4,.uk-light .uk-h5,.uk-light .uk-h6,.uk-light .uk-heading-2xlarge,.uk-light .uk-heading-3xlarge,.uk-light .uk-heading-large,.uk-light .uk-heading-medium,.uk-light .uk-heading-small,.uk-light .uk-heading-xlarge,.uk-light h1,.uk-light h2,.uk-light h3,.uk-light h4,.uk-light h5,.uk-light h6,.uk-offcanvas-bar .uk-h1,.uk-offcanvas-bar .uk-h2,.uk-offcanvas-bar .uk-h3,.uk-offcanvas-bar .uk-h4,.uk-offcanvas-bar .uk-h5,.uk-offcanvas-bar .uk-h6,.uk-offcanvas-bar .uk-heading-2xlarge,.uk-offcanvas-bar .uk-heading-3xlarge,.uk-offcanvas-bar .uk-heading-large,.uk-offcanvas-bar .uk-heading-medium,.uk-offcanvas-bar .uk-heading-small,.uk-offcanvas-bar .uk-heading-xlarge,.uk-offcanvas-bar h1,.uk-offcanvas-bar h2,.uk-offcanvas-bar h3,.uk-offcanvas-bar h4,.uk-offcanvas-bar h5,.uk-offcanvas-bar h6,.uk-overlay-primary .uk-h1,.uk-overlay-primary .uk-h2,.uk-overlay-primary .uk-h3,.uk-overlay-primary .uk-h4,.uk-overlay-primary .uk-h5,.uk-overlay-primary .uk-h6,.uk-overlay-primary .uk-heading-2xlarge,.uk-overlay-primary .uk-heading-3xlarge,.uk-overlay-primary .uk-heading-large,.uk-overlay-primary .uk-heading-medium,.uk-overlay-primary .uk-heading-small,.uk-overlay-primary .uk-heading-xlarge,.uk-overlay-primary h1,.uk-overlay-primary h2,.uk-overlay-primary h3,.uk-overlay-primary h4,.uk-overlay-primary h5,.uk-overlay-primary h6,.uk-section-primary:not(.uk-preserve-color) .uk-h1,.uk-section-primary:not(.uk-preserve-color) .uk-h2,.uk-section-primary:not(.uk-preserve-color) .uk-h3,.uk-section-primary:not(.uk-preserve-color) .uk-h4,.uk-section-primary:not(.uk-preserve-color) .uk-h5,.uk-section-primary:not(.uk-preserve-color) .uk-h6,.uk-section-primary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-section-primary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-section-primary:not(.uk-preserve-color) .uk-heading-large,.uk-section-primary:not(.uk-preserve-color) .uk-heading-medium,.uk-section-primary:not(.uk-preserve-color) .uk-heading-small,.uk-section-primary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-section-primary:not(.uk-preserve-color) h1,.uk-section-primary:not(.uk-preserve-color) h2,.uk-section-primary:not(.uk-preserve-color) h3,.uk-section-primary:not(.uk-preserve-color) h4,.uk-section-primary:not(.uk-preserve-color) h5,.uk-section-primary:not(.uk-preserve-color) h6,.uk-section-secondary:not(.uk-preserve-color) .uk-h1,.uk-section-secondary:not(.uk-preserve-color) .uk-h2,.uk-section-secondary:not(.uk-preserve-color) .uk-h3,.uk-section-secondary:not(.uk-preserve-color) .uk-h4,.uk-section-secondary:not(.uk-preserve-color) .uk-h5,.uk-section-secondary:not(.uk-preserve-color) .uk-h6,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-large,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-medium,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-small,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-section-secondary:not(.uk-preserve-color) h1,.uk-section-secondary:not(.uk-preserve-color) h2,.uk-section-secondary:not(.uk-preserve-color) h3,.uk-section-secondary:not(.uk-preserve-color) h4,.uk-section-secondary:not(.uk-preserve-color) h5,.uk-section-secondary:not(.uk-preserve-color) h6,.uk-tile-primary:not(.uk-preserve-color) .uk-h1,.uk-tile-primary:not(.uk-preserve-color) .uk-h2,.uk-tile-primary:not(.uk-preserve-color) .uk-h3,.uk-tile-primary:not(.uk-preserve-color) .uk-h4,.uk-tile-primary:not(.uk-preserve-color) .uk-h5,.uk-tile-primary:not(.uk-preserve-color) .uk-h6,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-large,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-medium,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-small,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-tile-primary:not(.uk-preserve-color) h1,.uk-tile-primary:not(.uk-preserve-color) h2,.uk-tile-primary:not(.uk-preserve-color) h3,.uk-tile-primary:not(.uk-preserve-color) h4,.uk-tile-primary:not(.uk-preserve-color) h5,.uk-tile-primary:not(.uk-preserve-color) h6,.uk-tile-secondary:not(.uk-preserve-color) .uk-h1,.uk-tile-secondary:not(.uk-preserve-color) .uk-h2,.uk-tile-secondary:not(.uk-preserve-color) .uk-h3,.uk-tile-secondary:not(.uk-preserve-color) .uk-h4,.uk-tile-secondary:not(.uk-preserve-color) .uk-h5,.uk-tile-secondary:not(.uk-preserve-color) .uk-h6,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-large,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-medium,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-small,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-tile-secondary:not(.uk-preserve-color) h1,.uk-tile-secondary:not(.uk-preserve-color) h2,.uk-tile-secondary:not(.uk-preserve-color) h3,.uk-tile-secondary:not(.uk-preserve-color) h4,.uk-tile-secondary:not(.uk-preserve-color) h5,.uk-tile-secondary:not(.uk-preserve-color) h6{color:#fff}.uk-card-primary.uk-card-body blockquote,.uk-card-primary>:not([class*=uk-card-media]) blockquote,.uk-card-secondary.uk-card-body blockquote,.uk-card-secondary>:not([class*=uk-card-media]) blockquote,.uk-light blockquote,.uk-offcanvas-bar blockquote,.uk-overlay-primary blockquote,.uk-section-primary:not(.uk-preserve-color) blockquote,.uk-section-secondary:not(.uk-preserve-color) blockquote,.uk-tile-primary:not(.uk-preserve-color) blockquote,.uk-tile-secondary:not(.uk-preserve-color) blockquote{color:#fff}.uk-card-primary.uk-card-body blockquote footer,.uk-card-primary>:not([class*=uk-card-media]) blockquote footer,.uk-card-secondary.uk-card-body blockquote footer,.uk-card-secondary>:not([class*=uk-card-media]) blockquote footer,.uk-light blockquote footer,.uk-offcanvas-bar blockquote footer,.uk-overlay-primary blockquote footer,.uk-section-primary:not(.uk-preserve-color) blockquote footer,.uk-section-secondary:not(.uk-preserve-color) blockquote footer,.uk-tile-primary:not(.uk-preserve-color) blockquote footer,.uk-tile-secondary:not(.uk-preserve-color) blockquote footer{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-hr,.uk-card-primary.uk-card-body hr,.uk-card-primary>:not([class*=uk-card-media]) .uk-hr,.uk-card-primary>:not([class*=uk-card-media]) hr,.uk-card-secondary.uk-card-body .uk-hr,.uk-card-secondary.uk-card-body hr,.uk-card-secondary>:not([class*=uk-card-media]) .uk-hr,.uk-card-secondary>:not([class*=uk-card-media]) hr,.uk-light .uk-hr,.uk-light hr,.uk-offcanvas-bar .uk-hr,.uk-offcanvas-bar hr,.uk-overlay-primary .uk-hr,.uk-overlay-primary hr,.uk-section-primary:not(.uk-preserve-color) .uk-hr,.uk-section-primary:not(.uk-preserve-color) hr,.uk-section-secondary:not(.uk-preserve-color) .uk-hr,.uk-section-secondary:not(.uk-preserve-color) hr,.uk-tile-primary:not(.uk-preserve-color) .uk-hr,.uk-tile-primary:not(.uk-preserve-color) hr,.uk-tile-secondary:not(.uk-preserve-color) .uk-hr,.uk-tile-secondary:not(.uk-preserve-color) hr{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body :focus-visible,.uk-card-primary>:not([class*=uk-card-media]) :focus-visible,.uk-card-secondary.uk-card-body :focus-visible,.uk-card-secondary>:not([class*=uk-card-media]) :focus-visible,.uk-light :focus-visible,.uk-offcanvas-bar :focus-visible,.uk-overlay-primary :focus-visible,.uk-section-primary:not(.uk-preserve-color) :focus-visible,.uk-section-secondary:not(.uk-preserve-color) :focus-visible,.uk-tile-primary:not(.uk-preserve-color) :focus-visible,.uk-tile-secondary:not(.uk-preserve-color) :focus-visible{outline-color:#fff}.uk-card-primary.uk-card-body .uk-link-muted a,.uk-card-primary.uk-card-body a.uk-link-muted,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted a,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-muted,.uk-card-secondary.uk-card-body .uk-link-muted a,.uk-card-secondary.uk-card-body a.uk-link-muted,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted a,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-muted,.uk-light .uk-link-muted a,.uk-light a.uk-link-muted,.uk-offcanvas-bar .uk-link-muted a,.uk-offcanvas-bar a.uk-link-muted,.uk-overlay-primary .uk-link-muted a,.uk-overlay-primary a.uk-link-muted,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted a,.uk-section-primary:not(.uk-preserve-color) a.uk-link-muted,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted a,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-muted,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted a,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-muted,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted a,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-muted{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-link-muted a:hover,.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link-muted,.uk-card-primary.uk-card-body a.uk-link-muted:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-muted,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-muted:hover,.uk-card-secondary.uk-card-body .uk-link-muted a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link-muted,.uk-card-secondary.uk-card-body a.uk-link-muted:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-muted,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-muted:hover,.uk-light .uk-link-muted a:hover,.uk-light .uk-link-toggle:hover .uk-link-muted,.uk-light a.uk-link-muted:hover,.uk-offcanvas-bar .uk-link-muted a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link-muted,.uk-offcanvas-bar a.uk-link-muted:hover,.uk-overlay-primary .uk-link-muted a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link-muted,.uk-overlay-primary a.uk-link-muted:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-section-primary:not(.uk-preserve-color) a.uk-link-muted:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-muted:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-muted:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-muted:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-link-text a:hover,.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link-text,.uk-card-primary.uk-card-body a.uk-link-text:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-text a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-text,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-text:hover,.uk-card-secondary.uk-card-body .uk-link-text a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link-text,.uk-card-secondary.uk-card-body a.uk-link-text:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-text a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-text,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-text:hover,.uk-light .uk-link-text a:hover,.uk-light .uk-link-toggle:hover .uk-link-text,.uk-light a.uk-link-text:hover,.uk-offcanvas-bar .uk-link-text a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link-text,.uk-offcanvas-bar a.uk-link-text:hover,.uk-overlay-primary .uk-link-text a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link-text,.uk-overlay-primary a.uk-link-text:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-section-primary:not(.uk-preserve-color) a.uk-link-text:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-text:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-text:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-text:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-link-heading a:hover,.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link-heading,.uk-card-primary.uk-card-body a.uk-link-heading:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-heading a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-heading,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-heading:hover,.uk-card-secondary.uk-card-body .uk-link-heading a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link-heading,.uk-card-secondary.uk-card-body a.uk-link-heading:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-heading a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-heading,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-heading:hover,.uk-light .uk-link-heading a:hover,.uk-light .uk-link-toggle:hover .uk-link-heading,.uk-light a.uk-link-heading:hover,.uk-offcanvas-bar .uk-link-heading a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link-heading,.uk-offcanvas-bar a.uk-link-heading:hover,.uk-overlay-primary .uk-link-heading a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link-heading,.uk-overlay-primary a.uk-link-heading:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-section-primary:not(.uk-preserve-color) a.uk-link-heading:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-heading:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-heading:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-heading:hover{color:#fff}.uk-card-primary.uk-card-body .uk-heading-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-divider,.uk-card-secondary.uk-card-body .uk-heading-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-divider,.uk-light .uk-heading-divider,.uk-offcanvas-bar .uk-heading-divider,.uk-overlay-primary .uk-heading-divider,.uk-section-primary:not(.uk-preserve-color) .uk-heading-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-divider{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-heading-bullet::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-bullet::before,.uk-card-secondary.uk-card-body .uk-heading-bullet::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-bullet::before,.uk-light .uk-heading-bullet::before,.uk-offcanvas-bar .uk-heading-bullet::before,.uk-overlay-primary .uk-heading-bullet::before,.uk-section-primary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-bullet::before{border-right-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-heading-line>::after,.uk-card-primary.uk-card-body .uk-heading-line>::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-line>::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-line>::before,.uk-card-secondary.uk-card-body .uk-heading-line>::after,.uk-card-secondary.uk-card-body .uk-heading-line>::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-line>::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-line>::before,.uk-light .uk-heading-line>::after,.uk-light .uk-heading-line>::before,.uk-offcanvas-bar .uk-heading-line>::after,.uk-offcanvas-bar .uk-heading-line>::before,.uk-overlay-primary .uk-heading-line>::after,.uk-overlay-primary .uk-heading-line>::before,.uk-section-primary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-section-primary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-line>::before{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon,.uk-card-secondary.uk-card-body .uk-divider-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon,.uk-light .uk-divider-icon,.uk-offcanvas-bar .uk-divider-icon,.uk-overlay-primary .uk-divider-icon,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22rgba%28255,%20255,%20255,%200.2%29%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-divider-icon::after,.uk-card-primary.uk-card-body .uk-divider-icon::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon::before,.uk-card-secondary.uk-card-body .uk-divider-icon::after,.uk-card-secondary.uk-card-body .uk-divider-icon::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon::before,.uk-light .uk-divider-icon::after,.uk-light .uk-divider-icon::before,.uk-offcanvas-bar .uk-divider-icon::after,.uk-offcanvas-bar .uk-divider-icon::before,.uk-overlay-primary .uk-divider-icon::after,.uk-overlay-primary .uk-divider-icon::before,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon::before{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-small::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-small::after,.uk-card-secondary.uk-card-body .uk-divider-small::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-small::after,.uk-light .uk-divider-small::after,.uk-offcanvas-bar .uk-divider-small::after,.uk-overlay-primary .uk-divider-small::after,.uk-section-primary:not(.uk-preserve-color) .uk-divider-small::after,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-small::after,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-small::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-small::after{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-vertical,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-vertical,.uk-card-secondary.uk-card-body .uk-divider-vertical,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-vertical,.uk-light .uk-divider-vertical,.uk-offcanvas-bar .uk-divider-vertical,.uk-overlay-primary .uk-divider-vertical,.uk-section-primary:not(.uk-preserve-color) .uk-divider-vertical,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-vertical,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-vertical,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-vertical{border-right-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-muted>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-muted>::marker,.uk-card-secondary.uk-card-body .uk-list-muted>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-muted>::marker,.uk-light .uk-list-muted>::marker,.uk-offcanvas-bar .uk-list-muted>::marker,.uk-overlay-primary .uk-list-muted>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-muted>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-muted>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-muted>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-muted>::marker{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-list-emphasis>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-emphasis>::marker,.uk-card-secondary.uk-card-body .uk-list-emphasis>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-emphasis>::marker,.uk-light .uk-list-emphasis>::marker,.uk-offcanvas-bar .uk-list-emphasis>::marker,.uk-overlay-primary .uk-list-emphasis>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-emphasis>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-emphasis>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-emphasis>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-emphasis>::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-primary>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-primary>::marker,.uk-card-secondary.uk-card-body .uk-list-primary>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-primary>::marker,.uk-light .uk-list-primary>::marker,.uk-offcanvas-bar .uk-list-primary>::marker,.uk-overlay-primary .uk-list-primary>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-primary>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-primary>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-primary>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-primary>::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-secondary>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-secondary>::marker,.uk-card-secondary.uk-card-body .uk-list-secondary>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-secondary>::marker,.uk-light .uk-list-secondary>::marker,.uk-offcanvas-bar .uk-list-secondary>::marker,.uk-overlay-primary .uk-list-secondary>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-secondary>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-secondary>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-secondary>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-secondary>::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-bullet>::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-bullet>::before,.uk-card-secondary.uk-card-body .uk-list-bullet>::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-bullet>::before,.uk-light .uk-list-bullet>::before,.uk-offcanvas-bar .uk-list-bullet>::before,.uk-overlay-primary .uk-list-bullet>::before,.uk-section-primary:not(.uk-preserve-color) .uk-list-bullet>::before,.uk-section-secondary:not(.uk-preserve-color) .uk-list-bullet>::before,.uk-tile-primary:not(.uk-preserve-color) .uk-list-bullet>::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-bullet>::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-list-divider>:nth-child(n+2),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-divider>:nth-child(n+2),.uk-card-secondary.uk-card-body .uk-list-divider>:nth-child(n+2),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-divider>:nth-child(n+2),.uk-light .uk-list-divider>:nth-child(n+2),.uk-offcanvas-bar .uk-list-divider>:nth-child(n+2),.uk-overlay-primary .uk-list-divider>:nth-child(n+2),.uk-section-primary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2),.uk-section-secondary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2),.uk-tile-primary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-light .uk-list-striped>:nth-of-type(odd),.uk-offcanvas-bar .uk-list-striped>:nth-of-type(odd),.uk-overlay-primary .uk-list-striped>:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd){border-top-color:rgba(255,255,255,.2);border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-light .uk-list-striped>:nth-of-type(odd),.uk-offcanvas-bar .uk-list-striped>:nth-of-type(odd),.uk-overlay-primary .uk-list-striped>:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd){background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-table th,.uk-card-primary>:not([class*=uk-card-media]) .uk-table th,.uk-card-secondary.uk-card-body .uk-table th,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table th,.uk-light .uk-table th,.uk-offcanvas-bar .uk-table th,.uk-overlay-primary .uk-table th,.uk-section-primary:not(.uk-preserve-color) .uk-table th,.uk-section-secondary:not(.uk-preserve-color) .uk-table th,.uk-tile-primary:not(.uk-preserve-color) .uk-table th,.uk-tile-secondary:not(.uk-preserve-color) .uk-table th{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-table caption,.uk-card-primary>:not([class*=uk-card-media]) .uk-table caption,.uk-card-secondary.uk-card-body .uk-table caption,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table caption,.uk-light .uk-table caption,.uk-offcanvas-bar .uk-table caption,.uk-overlay-primary .uk-table caption,.uk-section-primary:not(.uk-preserve-color) .uk-table caption,.uk-section-secondary:not(.uk-preserve-color) .uk-table caption,.uk-tile-primary:not(.uk-preserve-color) .uk-table caption,.uk-tile-secondary:not(.uk-preserve-color) .uk-table caption{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-table tbody tr.uk-active,.uk-card-primary.uk-card-body .uk-table>tr.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-table tbody tr.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-table>tr.uk-active,.uk-card-secondary.uk-card-body .uk-table tbody tr.uk-active,.uk-card-secondary.uk-card-body .uk-table>tr.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table tbody tr.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table>tr.uk-active,.uk-light .uk-table tbody tr.uk-active,.uk-light .uk-table>tr.uk-active,.uk-offcanvas-bar .uk-table tbody tr.uk-active,.uk-offcanvas-bar .uk-table>tr.uk-active,.uk-overlay-primary .uk-table tbody tr.uk-active,.uk-overlay-primary .uk-table>tr.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-table>tr.uk-active{background:rgba(255,255,255,.08)}.uk-card-primary.uk-card-body .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-primary.uk-card-body .uk-table-divider>:not(:first-child)>tr,.uk-card-primary.uk-card-body .uk-table-divider>tr:not(:first-child),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>:not(:first-child)>tr,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>tr:not(:first-child),.uk-card-secondary.uk-card-body .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-secondary.uk-card-body .uk-table-divider>:not(:first-child)>tr,.uk-card-secondary.uk-card-body .uk-table-divider>tr:not(:first-child),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>:not(:first-child)>tr,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>tr:not(:first-child),.uk-light .uk-table-divider>:first-child>tr:not(:first-child),.uk-light .uk-table-divider>:not(:first-child)>tr,.uk-light .uk-table-divider>tr:not(:first-child),.uk-offcanvas-bar .uk-table-divider>:first-child>tr:not(:first-child),.uk-offcanvas-bar .uk-table-divider>:not(:first-child)>tr,.uk-offcanvas-bar .uk-table-divider>tr:not(:first-child),.uk-overlay-primary .uk-table-divider>:first-child>tr:not(:first-child),.uk-overlay-primary .uk-table-divider>:not(:first-child)>tr,.uk-overlay-primary .uk-table-divider>tr:not(:first-child),.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-primary.uk-card-body .uk-table-striped>tr:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-table-striped>tr:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(odd),.uk-light .uk-table-striped tbody tr:nth-of-type(odd),.uk-light .uk-table-striped>tr:nth-of-type(odd),.uk-offcanvas-bar .uk-table-striped tbody tr:nth-of-type(odd),.uk-offcanvas-bar .uk-table-striped>tr:nth-of-type(odd),.uk-overlay-primary .uk-table-striped tbody tr:nth-of-type(odd),.uk-overlay-primary .uk-table-striped>tr:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd){background:rgba(255,255,255,.1);border-top-color:rgba(255,255,255,.2);border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-table-hover tbody tr:hover,.uk-card-primary.uk-card-body .uk-table-hover>tr:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-hover tbody tr:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-hover>tr:hover,.uk-card-secondary.uk-card-body .uk-table-hover tbody tr:hover,.uk-card-secondary.uk-card-body .uk-table-hover>tr:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-hover tbody tr:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-hover>tr:hover,.uk-light .uk-table-hover tbody tr:hover,.uk-light .uk-table-hover>tr:hover,.uk-offcanvas-bar .uk-table-hover tbody tr:hover,.uk-offcanvas-bar .uk-table-hover>tr:hover,.uk-overlay-primary .uk-table-hover tbody tr:hover,.uk-overlay-primary .uk-table-hover>tr:hover,.uk-section-primary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-section-primary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-hover>tr:hover{background:rgba(255,255,255,.08)}.uk-card-primary.uk-card-body .uk-icon-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link,.uk-card-secondary.uk-card-body .uk-icon-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link,.uk-light .uk-icon-link,.uk-offcanvas-bar .uk-icon-link,.uk-overlay-primary .uk-icon-link,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-icon-link:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:hover,.uk-card-secondary.uk-card-body .uk-icon-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:hover,.uk-light .uk-icon-link:hover,.uk-offcanvas-bar .uk-icon-link:hover,.uk-overlay-primary .uk-icon-link:hover,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-active>.uk-icon-link,.uk-card-primary.uk-card-body .uk-icon-link:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-active>.uk-icon-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:active,.uk-card-secondary.uk-card-body .uk-active>.uk-icon-link,.uk-card-secondary.uk-card-body .uk-icon-link:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-active>.uk-icon-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:active,.uk-light .uk-active>.uk-icon-link,.uk-light .uk-icon-link:active,.uk-offcanvas-bar .uk-active>.uk-icon-link,.uk-offcanvas-bar .uk-icon-link:active,.uk-overlay-primary .uk-active>.uk-icon-link,.uk-overlay-primary .uk-icon-link:active,.uk-section-primary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:active,.uk-section-secondary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:active,.uk-tile-primary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:active{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-icon-button,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button,.uk-card-secondary.uk-card-body .uk-icon-button,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button,.uk-light .uk-icon-button,.uk-offcanvas-bar .uk-icon-button,.uk-overlay-primary .uk-icon-button,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-icon-button:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:hover,.uk-card-secondary.uk-card-body .uk-icon-button:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:hover,.uk-light .uk-icon-button:hover,.uk-offcanvas-bar .uk-icon-button:hover,.uk-overlay-primary .uk-icon-button:hover,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:hover{background-color:rgba(255,255,255,.15);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-icon-button:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:active,.uk-card-secondary.uk-card-body .uk-icon-button:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:active,.uk-light .uk-icon-button:active,.uk-offcanvas-bar .uk-icon-button:active,.uk-overlay-primary .uk-icon-button:active,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:active,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:active,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:active{background-color:rgba(255,255,255,.2);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-range::-webkit-slider-runnable-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-runnable-track,.uk-card-secondary.uk-card-body .uk-range::-webkit-slider-runnable-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-runnable-track,.uk-light .uk-range::-webkit-slider-runnable-track,.uk-offcanvas-bar .uk-range::-webkit-slider-runnable-track,.uk-overlay-primary .uk-range::-webkit-slider-runnable-track,.uk-section-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track{background:rgba(242,242,242,.1)}.uk-card-primary.uk-card-body .uk-range:active::-webkit-slider-runnable-track,.uk-card-primary.uk-card-body .uk-range:focus::-webkit-slider-runnable-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range:active::-webkit-slider-runnable-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range:focus::-webkit-slider-runnable-track,.uk-card-secondary.uk-card-body .uk-range:active::-webkit-slider-runnable-track,.uk-card-secondary.uk-card-body .uk-range:focus::-webkit-slider-runnable-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range:active::-webkit-slider-runnable-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range:focus::-webkit-slider-runnable-track,.uk-light .uk-range:active::-webkit-slider-runnable-track,.uk-light .uk-range:focus::-webkit-slider-runnable-track,.uk-offcanvas-bar .uk-range:active::-webkit-slider-runnable-track,.uk-offcanvas-bar .uk-range:focus::-webkit-slider-runnable-track,.uk-overlay-primary .uk-range:active::-webkit-slider-runnable-track,.uk-overlay-primary .uk-range:focus::-webkit-slider-runnable-track,.uk-section-primary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-section-primary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track{background:rgba(242,242,242,.15)}.uk-card-primary.uk-card-body .uk-range::-moz-range-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-moz-range-track,.uk-card-secondary.uk-card-body .uk-range::-moz-range-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-moz-range-track,.uk-light .uk-range::-moz-range-track,.uk-offcanvas-bar .uk-range::-moz-range-track,.uk-overlay-primary .uk-range::-moz-range-track,.uk-section-primary:not(.uk-preserve-color) .uk-range::-moz-range-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-moz-range-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-moz-range-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-moz-range-track{background:rgba(242,242,242,.1)}.uk-card-primary.uk-card-body .uk-range:focus::-moz-range-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range:focus::-moz-range-track,.uk-card-secondary.uk-card-body .uk-range:focus::-moz-range-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range:focus::-moz-range-track,.uk-light .uk-range:focus::-moz-range-track,.uk-offcanvas-bar .uk-range:focus::-moz-range-track,.uk-overlay-primary .uk-range:focus::-moz-range-track,.uk-section-primary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track{background:rgba(242,242,242,.15)}.uk-card-primary.uk-card-body .uk-range::-webkit-slider-thumb,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-thumb,.uk-card-secondary.uk-card-body .uk-range::-webkit-slider-thumb,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-thumb,.uk-light .uk-range::-webkit-slider-thumb,.uk-offcanvas-bar .uk-range::-webkit-slider-thumb,.uk-overlay-primary .uk-range::-webkit-slider-thumb,.uk-section-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb{background:grey;border-color:#e6e6e6}.uk-card-primary.uk-card-body .uk-range::-moz-range-thumb,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-moz-range-thumb,.uk-card-secondary.uk-card-body .uk-range::-moz-range-thumb,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-moz-range-thumb,.uk-light .uk-range::-moz-range-thumb,.uk-offcanvas-bar .uk-range::-moz-range-thumb,.uk-overlay-primary .uk-range::-moz-range-thumb,.uk-section-primary:not(.uk-preserve-color) .uk-range::-moz-range-thumb,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-moz-range-thumb,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-moz-range-thumb,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-moz-range-thumb{background:grey;border-color:#e6e6e6}.uk-card-primary.uk-card-body .uk-input,.uk-card-primary.uk-card-body .uk-select,.uk-card-primary.uk-card-body .uk-textarea,.uk-card-primary>:not([class*=uk-card-media]) .uk-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-select,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea,.uk-card-secondary.uk-card-body .uk-input,.uk-card-secondary.uk-card-body .uk-select,.uk-card-secondary.uk-card-body .uk-textarea,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-select,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea,.uk-light .uk-input,.uk-light .uk-select,.uk-light .uk-textarea,.uk-offcanvas-bar .uk-input,.uk-offcanvas-bar .uk-select,.uk-offcanvas-bar .uk-textarea,.uk-overlay-primary .uk-input,.uk-overlay-primary .uk-select,.uk-overlay-primary .uk-textarea,.uk-section-primary:not(.uk-preserve-color) .uk-input,.uk-section-primary:not(.uk-preserve-color) .uk-select,.uk-section-primary:not(.uk-preserve-color) .uk-textarea,.uk-section-secondary:not(.uk-preserve-color) .uk-input,.uk-section-secondary:not(.uk-preserve-color) .uk-select,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea,.uk-tile-primary:not(.uk-preserve-color) .uk-input,.uk-tile-primary:not(.uk-preserve-color) .uk-select,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea,.uk-tile-secondary:not(.uk-preserve-color) .uk-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-select,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7);background-clip:padding-box;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-input:focus,.uk-card-primary.uk-card-body .uk-select:focus,.uk-card-primary.uk-card-body .uk-textarea:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-select:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea:focus,.uk-card-secondary.uk-card-body .uk-input:focus,.uk-card-secondary.uk-card-body .uk-select:focus,.uk-card-secondary.uk-card-body .uk-textarea:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-select:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea:focus,.uk-light .uk-input:focus,.uk-light .uk-select:focus,.uk-light .uk-textarea:focus,.uk-offcanvas-bar .uk-input:focus,.uk-offcanvas-bar .uk-select:focus,.uk-offcanvas-bar .uk-textarea:focus,.uk-overlay-primary .uk-input:focus,.uk-overlay-primary .uk-select:focus,.uk-overlay-primary .uk-textarea:focus,.uk-section-primary:not(.uk-preserve-color) .uk-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-select:focus,.uk-section-primary:not(.uk-preserve-color) .uk-textarea:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-select:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-select:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-select:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea:focus{background-color:rgba(255,255,255,.15);color:rgba(255,255,255,.7);border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-input::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-input::placeholder,.uk-card-secondary.uk-card-body .uk-input::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input::placeholder,.uk-light .uk-input::placeholder,.uk-offcanvas-bar .uk-input::placeholder,.uk-overlay-primary .uk-input::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-input::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-input::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-input::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-input::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-textarea::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea::placeholder,.uk-card-secondary.uk-card-body .uk-textarea::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea::placeholder,.uk-light .uk-textarea::placeholder,.uk-offcanvas-bar .uk-textarea::placeholder,.uk-overlay-primary .uk-textarea::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-select:not([multiple]):not([size]),.uk-card-primary>:not([class*=uk-card-media]) .uk-select:not([multiple]):not([size]),.uk-card-secondary.uk-card-body .uk-select:not([multiple]):not([size]),.uk-card-secondary>:not([class*=uk-card-media]) .uk-select:not([multiple]):not([size]),.uk-light .uk-select:not([multiple]):not([size]),.uk-offcanvas-bar .uk-select:not([multiple]):not([size]),.uk-overlay-primary .uk-select:not([multiple]):not([size]),.uk-section-primary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-section-secondary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-tile-primary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-tile-secondary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]){background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-input[list]:focus,.uk-card-primary.uk-card-body .uk-input[list]:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-input[list]:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-input[list]:hover,.uk-card-secondary.uk-card-body .uk-input[list]:focus,.uk-card-secondary.uk-card-body .uk-input[list]:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input[list]:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input[list]:hover,.uk-light .uk-input[list]:focus,.uk-light .uk-input[list]:hover,.uk-offcanvas-bar .uk-input[list]:focus,.uk-offcanvas-bar .uk-input[list]:hover,.uk-overlay-primary .uk-input[list]:focus,.uk-overlay-primary .uk-input[list]:hover,.uk-section-primary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-section-primary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-input[list]:hover{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-checkbox,.uk-card-primary.uk-card-body .uk-radio,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio,.uk-card-secondary.uk-card-body .uk-checkbox,.uk-card-secondary.uk-card-body .uk-radio,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio,.uk-light .uk-checkbox,.uk-light .uk-radio,.uk-offcanvas-bar .uk-checkbox,.uk-offcanvas-bar .uk-radio,.uk-overlay-primary .uk-checkbox,.uk-overlay-primary .uk-radio,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox,.uk-section-primary:not(.uk-preserve-color) .uk-radio,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox,.uk-section-secondary:not(.uk-preserve-color) .uk-radio,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox,.uk-tile-primary:not(.uk-preserve-color) .uk-radio,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio{background-color:rgba(255,255,255,.1);border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-checkbox:focus,.uk-card-primary.uk-card-body .uk-radio:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:focus,.uk-card-secondary.uk-card-body .uk-checkbox:focus,.uk-card-secondary.uk-card-body .uk-radio:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:focus,.uk-light .uk-checkbox:focus,.uk-light .uk-radio:focus,.uk-offcanvas-bar .uk-checkbox:focus,.uk-offcanvas-bar .uk-radio:focus,.uk-overlay-primary .uk-checkbox:focus,.uk-overlay-primary .uk-radio:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-section-primary:not(.uk-preserve-color) .uk-radio:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:focus{background-color:rgba(255,255,255,.15);border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-checkbox:checked,.uk-card-primary.uk-card-body .uk-checkbox:indeterminate,.uk-card-primary.uk-card-body .uk-radio:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-card-secondary.uk-card-body .uk-checkbox:checked,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate,.uk-card-secondary.uk-card-body .uk-radio:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-light .uk-checkbox:checked,.uk-light .uk-checkbox:indeterminate,.uk-light .uk-radio:checked,.uk-offcanvas-bar .uk-checkbox:checked,.uk-offcanvas-bar .uk-checkbox:indeterminate,.uk-offcanvas-bar .uk-radio:checked,.uk-overlay-primary .uk-checkbox:checked,.uk-overlay-primary .uk-checkbox:indeterminate,.uk-overlay-primary .uk-radio:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked{background-color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-checkbox:checked:focus,.uk-card-primary.uk-card-body .uk-checkbox:indeterminate:focus,.uk-card-primary.uk-card-body .uk-radio:checked:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked:focus,.uk-card-secondary.uk-card-body .uk-checkbox:checked:focus,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate:focus,.uk-card-secondary.uk-card-body .uk-radio:checked:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked:focus,.uk-light .uk-checkbox:checked:focus,.uk-light .uk-checkbox:indeterminate:focus,.uk-light .uk-radio:checked:focus,.uk-offcanvas-bar .uk-checkbox:checked:focus,.uk-offcanvas-bar .uk-checkbox:indeterminate:focus,.uk-offcanvas-bar .uk-radio:checked:focus,.uk-overlay-primary .uk-checkbox:checked:focus,.uk-overlay-primary .uk-checkbox:indeterminate:focus,.uk-overlay-primary .uk-radio:checked:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked:focus{background-color:#fff}.uk-card-primary.uk-card-body .uk-radio:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-card-secondary.uk-card-body .uk-radio:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-light .uk-radio:checked,.uk-offcanvas-bar .uk-radio:checked,.uk-overlay-primary .uk-radio:checked,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-checkbox:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-secondary.uk-card-body .uk-checkbox:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-light .uk-checkbox:checked,.uk-offcanvas-bar .uk-checkbox:checked,.uk-overlay-primary .uk-checkbox:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-checkbox:indeterminate,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-light .uk-checkbox:indeterminate,.uk-offcanvas-bar .uk-checkbox:indeterminate,.uk-overlay-primary .uk-checkbox:indeterminate,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-form-label,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-label,.uk-card-secondary.uk-card-body .uk-form-label,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-label,.uk-light .uk-form-label,.uk-offcanvas-bar .uk-form-label,.uk-overlay-primary .uk-form-label,.uk-section-primary:not(.uk-preserve-color) .uk-form-label,.uk-section-secondary:not(.uk-preserve-color) .uk-form-label,.uk-tile-primary:not(.uk-preserve-color) .uk-form-label,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-label{color:#fff}.uk-card-primary.uk-card-body .uk-form-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-icon,.uk-card-secondary.uk-card-body .uk-form-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-icon,.uk-light .uk-form-icon,.uk-offcanvas-bar .uk-form-icon,.uk-overlay-primary .uk-form-icon,.uk-section-primary:not(.uk-preserve-color) .uk-form-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-form-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-form-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-icon{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-form-icon:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-icon:hover,.uk-card-secondary.uk-card-body .uk-form-icon:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-icon:hover,.uk-light .uk-form-icon:hover,.uk-offcanvas-bar .uk-form-icon:hover,.uk-overlay-primary .uk-form-icon:hover,.uk-section-primary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-icon:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-button-default,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default,.uk-card-secondary.uk-card-body .uk-button-default,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default,.uk-light .uk-button-default,.uk-offcanvas-bar .uk-button-default,.uk-overlay-primary .uk-button-default,.uk-section-primary:not(.uk-preserve-color) .uk-button-default,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default{background-color:transparent;color:#fff;border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-button-default:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:hover,.uk-card-secondary.uk-card-body .uk-button-default:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:hover,.uk-light .uk-button-default:hover,.uk-offcanvas-bar .uk-button-default:hover,.uk-overlay-primary .uk-button-default:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:hover{background-color:transparent;color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-button-default.uk-active,.uk-card-primary.uk-card-body .uk-button-default:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:active,.uk-card-secondary.uk-card-body .uk-button-default.uk-active,.uk-card-secondary.uk-card-body .uk-button-default:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:active,.uk-light .uk-button-default.uk-active,.uk-light .uk-button-default:active,.uk-offcanvas-bar .uk-button-default.uk-active,.uk-offcanvas-bar .uk-button-default:active,.uk-overlay-primary .uk-button-default.uk-active,.uk-overlay-primary .uk-button-default:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:active{background-color:transparent;color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-button-primary,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary,.uk-card-secondary.uk-card-body .uk-button-primary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary,.uk-light .uk-button-primary,.uk-offcanvas-bar .uk-button-primary,.uk-overlay-primary .uk-button-primary,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-button-primary:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:hover,.uk-card-secondary.uk-card-body .uk-button-primary:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:hover,.uk-light .uk-button-primary:hover,.uk-offcanvas-bar .uk-button-primary:hover,.uk-overlay-primary .uk-button-primary:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:hover{background-color:#f2f2f2;color:#666}.uk-card-primary.uk-card-body .uk-button-primary.uk-active,.uk-card-primary.uk-card-body .uk-button-primary:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:active,.uk-card-secondary.uk-card-body .uk-button-primary.uk-active,.uk-card-secondary.uk-card-body .uk-button-primary:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:active,.uk-light .uk-button-primary.uk-active,.uk-light .uk-button-primary:active,.uk-offcanvas-bar .uk-button-primary.uk-active,.uk-offcanvas-bar .uk-button-primary:active,.uk-overlay-primary .uk-button-primary.uk-active,.uk-overlay-primary .uk-button-primary:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:active{background-color:#e6e6e6;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary,.uk-card-secondary.uk-card-body .uk-button-secondary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary,.uk-light .uk-button-secondary,.uk-offcanvas-bar .uk-button-secondary,.uk-overlay-primary .uk-button-secondary,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:hover,.uk-card-secondary.uk-card-body .uk-button-secondary:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:hover,.uk-light .uk-button-secondary:hover,.uk-offcanvas-bar .uk-button-secondary:hover,.uk-overlay-primary .uk-button-secondary:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:hover{background-color:#f2f2f2;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary.uk-active,.uk-card-primary.uk-card-body .uk-button-secondary:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:active,.uk-card-secondary.uk-card-body .uk-button-secondary.uk-active,.uk-card-secondary.uk-card-body .uk-button-secondary:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:active,.uk-light .uk-button-secondary.uk-active,.uk-light .uk-button-secondary:active,.uk-offcanvas-bar .uk-button-secondary.uk-active,.uk-offcanvas-bar .uk-button-secondary:active,.uk-overlay-primary .uk-button-secondary.uk-active,.uk-overlay-primary .uk-button-secondary:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:active{background-color:#e6e6e6;color:#666}.uk-card-primary.uk-card-body .uk-button-text,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text,.uk-card-secondary.uk-card-body .uk-button-text,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text,.uk-light .uk-button-text,.uk-offcanvas-bar .uk-button-text,.uk-overlay-primary .uk-button-text,.uk-section-primary:not(.uk-preserve-color) .uk-button-text,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text{color:#fff}.uk-card-primary.uk-card-body .uk-button-text::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text::before,.uk-card-secondary.uk-card-body .uk-button-text::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text::before,.uk-light .uk-button-text::before,.uk-offcanvas-bar .uk-button-text::before,.uk-overlay-primary .uk-button-text::before,.uk-section-primary:not(.uk-preserve-color) .uk-button-text::before,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text::before,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text::before{border-bottom-color:#fff}.uk-card-primary.uk-card-body .uk-button-text:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:hover,.uk-card-secondary.uk-card-body .uk-button-text:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:hover,.uk-light .uk-button-text:hover,.uk-offcanvas-bar .uk-button-text:hover,.uk-overlay-primary .uk-button-text:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:hover{color:#fff}.uk-card-primary.uk-card-body .uk-button-text:disabled,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:disabled,.uk-card-secondary.uk-card-body .uk-button-text:disabled,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:disabled,.uk-light .uk-button-text:disabled,.uk-offcanvas-bar .uk-button-text:disabled,.uk-overlay-primary .uk-button-text:disabled,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:disabled{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-button-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link,.uk-card-secondary.uk-card-body .uk-button-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link,.uk-light .uk-button-link,.uk-offcanvas-bar .uk-button-link,.uk-overlay-primary .uk-button-link,.uk-section-primary:not(.uk-preserve-color) .uk-button-link,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link{color:#fff}.uk-card-primary.uk-card-body .uk-button-link:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link:hover,.uk-card-secondary.uk-card-body .uk-button-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link:hover,.uk-light .uk-button-link:hover,.uk-offcanvas-bar .uk-button-link:hover,.uk-overlay-primary .uk-button-link:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-link:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body.uk-card-badge,.uk-card-primary>:not([class*=uk-card-media]).uk-card-badge,.uk-card-secondary.uk-card-body.uk-card-badge,.uk-card-secondary>:not([class*=uk-card-media]).uk-card-badge,.uk-light.uk-card-badge,.uk-offcanvas-bar.uk-card-badge,.uk-overlay-primary.uk-card-badge,.uk-section-primary:not(.uk-preserve-color).uk-card-badge,.uk-section-secondary:not(.uk-preserve-color).uk-card-badge,.uk-tile-primary:not(.uk-preserve-color).uk-card-badge,.uk-tile-secondary:not(.uk-preserve-color).uk-card-badge{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-close,.uk-card-primary>:not([class*=uk-card-media]) .uk-close,.uk-card-secondary.uk-card-body .uk-close,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close,.uk-light .uk-close,.uk-offcanvas-bar .uk-close,.uk-overlay-primary .uk-close,.uk-section-primary:not(.uk-preserve-color) .uk-close,.uk-section-secondary:not(.uk-preserve-color) .uk-close,.uk-tile-primary:not(.uk-preserve-color) .uk-close,.uk-tile-secondary:not(.uk-preserve-color) .uk-close{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-close:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-close:hover,.uk-card-secondary.uk-card-body .uk-close:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close:hover,.uk-light .uk-close:hover,.uk-offcanvas-bar .uk-close:hover,.uk-overlay-primary .uk-close:hover,.uk-section-primary:not(.uk-preserve-color) .uk-close:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-close:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-close:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-close:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-totop,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop,.uk-card-secondary.uk-card-body .uk-totop,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop,.uk-light .uk-totop,.uk-offcanvas-bar .uk-totop,.uk-overlay-primary .uk-totop,.uk-section-primary:not(.uk-preserve-color) .uk-totop,.uk-section-secondary:not(.uk-preserve-color) .uk-totop,.uk-tile-primary:not(.uk-preserve-color) .uk-totop,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-totop:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:hover,.uk-card-secondary.uk-card-body .uk-totop:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:hover,.uk-light .uk-totop:hover,.uk-offcanvas-bar .uk-totop:hover,.uk-overlay-primary .uk-totop:hover,.uk-section-primary:not(.uk-preserve-color) .uk-totop:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-totop:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:active,.uk-card-secondary.uk-card-body .uk-totop:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:active,.uk-light .uk-totop:active,.uk-offcanvas-bar .uk-totop:active,.uk-overlay-primary .uk-totop:active,.uk-section-primary:not(.uk-preserve-color) .uk-totop:active,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:active,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:active{color:#fff}.uk-card-primary.uk-card-body .uk-marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker,.uk-card-secondary.uk-card-body .uk-marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker,.uk-light .uk-marker,.uk-offcanvas-bar .uk-marker,.uk-overlay-primary .uk-marker,.uk-section-primary:not(.uk-preserve-color) .uk-marker,.uk-section-secondary:not(.uk-preserve-color) .uk-marker,.uk-tile-primary:not(.uk-preserve-color) .uk-marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker{background:#f8f8f8;color:#666}.uk-card-primary.uk-card-body .uk-marker:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker:hover,.uk-card-secondary.uk-card-body .uk-marker:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker:hover,.uk-light .uk-marker:hover,.uk-offcanvas-bar .uk-marker:hover,.uk-overlay-primary .uk-marker:hover,.uk-section-primary:not(.uk-preserve-color) .uk-marker:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-marker:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-marker:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker:hover{color:#666}.uk-card-primary.uk-card-body .uk-badge,.uk-card-primary>:not([class*=uk-card-media]) .uk-badge,.uk-card-secondary.uk-card-body .uk-badge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-badge,.uk-light .uk-badge,.uk-offcanvas-bar .uk-badge,.uk-overlay-primary .uk-badge,.uk-section-primary:not(.uk-preserve-color) .uk-badge,.uk-section-secondary:not(.uk-preserve-color) .uk-badge,.uk-tile-primary:not(.uk-preserve-color) .uk-badge,.uk-tile-secondary:not(.uk-preserve-color) .uk-badge{background-color:#fff;color:#666!important}.uk-card-primary.uk-card-body .uk-label,.uk-card-primary>:not([class*=uk-card-media]) .uk-label,.uk-card-secondary.uk-card-body .uk-label,.uk-card-secondary>:not([class*=uk-card-media]) .uk-label,.uk-light .uk-label,.uk-offcanvas-bar .uk-label,.uk-overlay-primary .uk-label,.uk-section-primary:not(.uk-preserve-color) .uk-label,.uk-section-secondary:not(.uk-preserve-color) .uk-label,.uk-tile-primary:not(.uk-preserve-color) .uk-label,.uk-tile-secondary:not(.uk-preserve-color) .uk-label{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-article-meta,.uk-card-primary>:not([class*=uk-card-media]) .uk-article-meta,.uk-card-secondary.uk-card-body .uk-article-meta,.uk-card-secondary>:not([class*=uk-card-media]) .uk-article-meta,.uk-light .uk-article-meta,.uk-offcanvas-bar .uk-article-meta,.uk-overlay-primary .uk-article-meta,.uk-section-primary:not(.uk-preserve-color) .uk-article-meta,.uk-section-secondary:not(.uk-preserve-color) .uk-article-meta,.uk-tile-primary:not(.uk-preserve-color) .uk-article-meta,.uk-tile-secondary:not(.uk-preserve-color) .uk-article-meta{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input,.uk-light .uk-search-input,.uk-offcanvas-bar .uk-search-input,.uk-overlay-primary .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-search-input::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input::placeholder,.uk-card-secondary.uk-card-body .uk-search-input::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input::placeholder,.uk-light .uk-search-input::placeholder,.uk-offcanvas-bar .uk-search-input::placeholder,.uk-overlay-primary .uk-search-input::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search .uk-search-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-search .uk-search-icon,.uk-card-secondary.uk-card-body .uk-search .uk-search-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search .uk-search-icon,.uk-light .uk-search .uk-search-icon,.uk-offcanvas-bar .uk-search .uk-search-icon,.uk-overlay-primary .uk-search .uk-search-icon,.uk-section-primary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search .uk-search-icon:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-search .uk-search-icon:hover,.uk-card-secondary.uk-card-body .uk-search .uk-search-icon:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search .uk-search-icon:hover,.uk-light .uk-search .uk-search-icon:hover,.uk-offcanvas-bar .uk-search .uk-search-icon:hover,.uk-overlay-primary .uk-search .uk-search-icon:hover,.uk-section-primary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-default .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-default .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input,.uk-light .uk-search-default .uk-search-input,.uk-offcanvas-bar .uk-search-default .uk-search-input,.uk-overlay-primary .uk-search-default .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-default .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-default .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input:focus,.uk-light .uk-search-default .uk-search-input:focus,.uk-offcanvas-bar .uk-search-default .uk-search-input:focus,.uk-overlay-primary .uk-search-default .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-navbar .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-navbar .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input,.uk-light .uk-search-navbar .uk-search-input,.uk-offcanvas-bar .uk-search-navbar .uk-search-input,.uk-overlay-primary .uk-search-navbar .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-navbar .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-navbar .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input:focus,.uk-light .uk-search-navbar .uk-search-input:focus,.uk-offcanvas-bar .uk-search-navbar .uk-search-input:focus,.uk-overlay-primary .uk-search-navbar .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-medium .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-medium .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input,.uk-light .uk-search-medium .uk-search-input,.uk-offcanvas-bar .uk-search-medium .uk-search-input,.uk-overlay-primary .uk-search-medium .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-medium .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-medium .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input:focus,.uk-light .uk-search-medium .uk-search-input:focus,.uk-offcanvas-bar .uk-search-medium .uk-search-input:focus,.uk-overlay-primary .uk-search-medium .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-large .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-large .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input,.uk-light .uk-search-large .uk-search-input,.uk-offcanvas-bar .uk-search-large .uk-search-input,.uk-overlay-primary .uk-search-large .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-large .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-large .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input:focus,.uk-light .uk-search-large .uk-search-input:focus,.uk-offcanvas-bar .uk-search-large .uk-search-input:focus,.uk-overlay-primary .uk-search-large .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-toggle,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle,.uk-card-secondary.uk-card-body .uk-search-toggle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle,.uk-light .uk-search-toggle,.uk-offcanvas-bar .uk-search-toggle,.uk-overlay-primary .uk-search-toggle,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-toggle:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle:hover,.uk-card-secondary.uk-card-body .uk-search-toggle:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle:hover,.uk-light .uk-search-toggle:hover,.uk-offcanvas-bar .uk-search-toggle:hover,.uk-overlay-primary .uk-search-toggle:hover,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-accordion-title,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title,.uk-card-secondary.uk-card-body .uk-accordion-title,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title,.uk-light .uk-accordion-title,.uk-offcanvas-bar .uk-accordion-title,.uk-overlay-primary .uk-accordion-title,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title{color:#fff}.uk-card-primary.uk-card-body .uk-accordion-title:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title:hover,.uk-card-secondary.uk-card-body .uk-accordion-title:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title:hover,.uk-light .uk-accordion-title:hover,.uk-offcanvas-bar .uk-accordion-title:hover,.uk-overlay-primary .uk-accordion-title:hover,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-thumbnav>*>::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-thumbnav>*>::after,.uk-card-secondary.uk-card-body .uk-thumbnav>*>::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-thumbnav>*>::after,.uk-light .uk-thumbnav>*>::after,.uk-offcanvas-bar .uk-thumbnav>*>::after,.uk-overlay-primary .uk-thumbnav>*>::after,.uk-section-primary:not(.uk-preserve-color) .uk-thumbnav>*>::after,.uk-section-secondary:not(.uk-preserve-color) .uk-thumbnav>*>::after,.uk-tile-primary:not(.uk-preserve-color) .uk-thumbnav>*>::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-thumbnav>*>::after{background-image:linear-gradient(-180deg,rgba(0,0,0,0),rgba(0,0,0,.4))}.uk-card-primary.uk-card-body .uk-iconnav>*>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a,.uk-card-secondary.uk-card-body .uk-iconnav>*>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a,.uk-light .uk-iconnav>*>a,.uk-offcanvas-bar .uk-iconnav>*>a,.uk-overlay-primary .uk-iconnav>*>a,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-iconnav>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a:hover,.uk-card-secondary.uk-card-body .uk-iconnav>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a:hover,.uk-light .uk-iconnav>*>a:hover,.uk-offcanvas-bar .uk-iconnav>*>a:hover,.uk-overlay-primary .uk-iconnav>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-iconnav>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>.uk-active>a,.uk-card-secondary.uk-card-body .uk-iconnav>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>.uk-active>a,.uk-light .uk-iconnav>.uk-active>a,.uk-offcanvas-bar .uk-iconnav>.uk-active>a,.uk-overlay-primary .uk-iconnav>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-grid-divider>:not(.uk-first-column)::before,.uk-light .uk-grid-divider>:not(.uk-first-column)::before,.uk-offcanvas-bar .uk-grid-divider>:not(.uk-first-column)::before,.uk-overlay-primary .uk-grid-divider>:not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before{border-right-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-secondary.uk-card-body .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-light .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-offcanvas-bar .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-overlay-primary .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-section-primary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-section-secondary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-tile-primary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-default>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a,.uk-card-secondary.uk-card-body .uk-nav-default>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a,.uk-light .uk-nav-default>li>a,.uk-offcanvas-bar .uk-nav-default>li>a,.uk-overlay-primary .uk-nav-default>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-default>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-default>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a:hover,.uk-light .uk-nav-default>li>a:hover,.uk-offcanvas-bar .uk-nav-default>li>a:hover,.uk-overlay-primary .uk-nav-default>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-default>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-default>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li.uk-active>a,.uk-light .uk-nav-default>li.uk-active>a,.uk-offcanvas-bar .uk-nav-default>li.uk-active>a,.uk-overlay-primary .uk-nav-default>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-header,.uk-light .uk-nav-default .uk-nav-header,.uk-offcanvas-bar .uk-nav-default .uk-nav-header,.uk-overlay-primary .uk-nav-default .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-divider,.uk-light .uk-nav-default .uk-nav-divider,.uk-offcanvas-bar .uk-nav-default .uk-nav-divider,.uk-overlay-primary .uk-nav-default .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a,.uk-light .uk-nav-default .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a,.uk-overlay-primary .uk-nav-default .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:hover,.uk-light .uk-nav-default .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-default .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a,.uk-light .uk-nav-primary>li>a,.uk-offcanvas-bar .uk-nav-primary>li>a,.uk-overlay-primary .uk-nav-primary>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-primary>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:hover,.uk-light .uk-nav-primary>li>a:hover,.uk-offcanvas-bar .uk-nav-primary>li>a:hover,.uk-overlay-primary .uk-nav-primary>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-primary>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-primary>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li.uk-active>a,.uk-light .uk-nav-primary>li.uk-active>a,.uk-offcanvas-bar .uk-nav-primary>li.uk-active>a,.uk-overlay-primary .uk-nav-primary>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-header,.uk-light .uk-nav-primary .uk-nav-header,.uk-offcanvas-bar .uk-nav-primary .uk-nav-header,.uk-overlay-primary .uk-nav-primary .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-divider,.uk-light .uk-nav-primary .uk-nav-divider,.uk-offcanvas-bar .uk-nav-primary .uk-nav-divider,.uk-overlay-primary .uk-nav-primary .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a,.uk-light .uk-nav-primary .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:hover,.uk-light .uk-nav-primary .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a,.uk-card-secondary.uk-card-body .uk-nav-secondary>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a,.uk-light .uk-nav-secondary>li>a,.uk-offcanvas-bar .uk-nav-secondary>li>a,.uk-overlay-primary .uk-nav-secondary>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-secondary>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover,.uk-light .uk-nav-secondary>li>a:hover,.uk-offcanvas-bar .uk-nav-secondary>li>a:hover,.uk-overlay-primary .uk-nav-secondary>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover{color:#fff;background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-nav-secondary>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-secondary>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a,.uk-light .uk-nav-secondary>li.uk-active>a,.uk-offcanvas-bar .uk-nav-secondary>li.uk-active>a,.uk-overlay-primary .uk-nav-secondary>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a{color:#fff;background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-subtitle,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-subtitle,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-subtitle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-subtitle,.uk-light .uk-nav-secondary .uk-nav-subtitle,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-subtitle,.uk-overlay-primary .uk-nav-secondary .uk-nav-subtitle,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-card-secondary.uk-card-body .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-light .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-offcanvas-bar .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-overlay-primary .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-card-secondary.uk-card-body .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-light .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-offcanvas-bar .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-overlay-primary .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-header,.uk-light .uk-nav-secondary .uk-nav-header,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-header,.uk-overlay-primary .uk-nav-secondary .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-divider,.uk-light .uk-nav-secondary .uk-nav-divider,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-divider,.uk-overlay-primary .uk-nav-secondary .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a,.uk-light .uk-nav-secondary .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-sub a,.uk-overlay-primary .uk-nav-secondary .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a:hover,.uk-light .uk-nav-secondary .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-secondary .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-card-primary>:not([class*=uk-card-media]) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-card-secondary.uk-card-body .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-light .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-offcanvas-bar .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-overlay-primary .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-section-primary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-section-secondary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-tile-primary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-tile-secondary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-navbar-nav>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a,.uk-light .uk-navbar-nav>li>a,.uk-offcanvas-bar .uk-navbar-nav>li>a,.uk-overlay-primary .uk-navbar-nav>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-navbar-nav>li:hover>a,.uk-card-primary.uk-card-body .uk-navbar-nav>li>a[aria-expanded=true],.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li:hover>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a[aria-expanded=true],.uk-card-secondary.uk-card-body .uk-navbar-nav>li:hover>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a[aria-expanded=true],.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li:hover>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a[aria-expanded=true],.uk-light .uk-navbar-nav>li:hover>a,.uk-light .uk-navbar-nav>li>a[aria-expanded=true],.uk-offcanvas-bar .uk-navbar-nav>li:hover>a,.uk-offcanvas-bar .uk-navbar-nav>li>a[aria-expanded=true],.uk-overlay-primary .uk-navbar-nav>li:hover>a,.uk-overlay-primary .uk-navbar-nav>li>a[aria-expanded=true],.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true],.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true],.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true],.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true]{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-navbar-nav>li>a:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:active,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:active,.uk-light .uk-navbar-nav>li>a:active,.uk-offcanvas-bar .uk-navbar-nav>li>a:active,.uk-overlay-primary .uk-navbar-nav>li>a:active,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-nav>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li.uk-active>a,.uk-light .uk-navbar-nav>li.uk-active>a,.uk-offcanvas-bar .uk-navbar-nav>li.uk-active>a,.uk-overlay-primary .uk-navbar-nav>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-item,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-item,.uk-card-secondary.uk-card-body .uk-navbar-item,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-item,.uk-light .uk-navbar-item,.uk-offcanvas-bar .uk-navbar-item,.uk-overlay-primary .uk-navbar-item,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-item,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-item,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-item,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-item{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-navbar-toggle,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle,.uk-card-secondary.uk-card-body .uk-navbar-toggle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle,.uk-light .uk-navbar-toggle,.uk-offcanvas-bar .uk-navbar-toggle,.uk-overlay-primary .uk-navbar-toggle,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-navbar-toggle:hover,.uk-card-primary.uk-card-body .uk-navbar-toggle[aria-expanded=true],.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle[aria-expanded=true],.uk-card-secondary.uk-card-body .uk-navbar-toggle:hover,.uk-card-secondary.uk-card-body .uk-navbar-toggle[aria-expanded=true],.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle[aria-expanded=true],.uk-light .uk-navbar-toggle:hover,.uk-light .uk-navbar-toggle[aria-expanded=true],.uk-offcanvas-bar .uk-navbar-toggle:hover,.uk-offcanvas-bar .uk-navbar-toggle[aria-expanded=true],.uk-overlay-primary .uk-navbar-toggle:hover,.uk-overlay-primary .uk-navbar-toggle[aria-expanded=true],.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true],.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true],.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true],.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true]{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav>*>:first-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>:first-child,.uk-card-secondary.uk-card-body .uk-subnav>*>:first-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>:first-child,.uk-light .uk-subnav>*>:first-child,.uk-offcanvas-bar .uk-subnav>*>:first-child,.uk-overlay-primary .uk-subnav>*>:first-child,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>:first-child{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-subnav>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>a:hover,.uk-card-secondary.uk-card-body .uk-subnav>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>a:hover,.uk-light .uk-subnav>*>a:hover,.uk-offcanvas-bar .uk-subnav>*>a:hover,.uk-overlay-primary .uk-subnav>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>.uk-active>a,.uk-card-secondary.uk-card-body .uk-subnav>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>.uk-active>a,.uk-light .uk-subnav>.uk-active>a,.uk-offcanvas-bar .uk-subnav>.uk-active>a,.uk-overlay-primary .uk-subnav>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-light .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-offcanvas-bar .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-overlay-primary .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{border-right-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>:first-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>:first-child,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>:first-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>:first-child,.uk-light .uk-subnav-pill>*>:first-child,.uk-offcanvas-bar .uk-subnav-pill>*>:first-child,.uk-overlay-primary .uk-subnav-pill>*>:first-child,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child{background-color:transparent;color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:hover,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:hover,.uk-light .uk-subnav-pill>*>a:hover,.uk-offcanvas-bar .uk-subnav-pill>*>a:hover,.uk-overlay-primary .uk-subnav-pill>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:active,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:active,.uk-light .uk-subnav-pill>*>a:active,.uk-offcanvas-bar .uk-subnav-pill>*>a:active,.uk-overlay-primary .uk-subnav-pill>*>a:active,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav-pill>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>.uk-active>a,.uk-card-secondary.uk-card-body .uk-subnav-pill>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>.uk-active>a,.uk-light .uk-subnav-pill>.uk-active>a,.uk-offcanvas-bar .uk-subnav-pill>.uk-active>a,.uk-overlay-primary .uk-subnav-pill>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-subnav>.uk-disabled>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>.uk-disabled>a,.uk-card-secondary.uk-card-body .uk-subnav>.uk-disabled>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>.uk-disabled>a,.uk-light .uk-subnav>.uk-disabled>a,.uk-offcanvas-bar .uk-subnav>.uk-disabled>a,.uk-overlay-primary .uk-subnav>.uk-disabled>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-breadcrumb>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>*,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>*,.uk-light .uk-breadcrumb>*>*,.uk-offcanvas-bar .uk-breadcrumb>*>*,.uk-overlay-primary .uk-breadcrumb>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-breadcrumb>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:hover,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:hover,.uk-light .uk-breadcrumb>*>:hover,.uk-offcanvas-bar .uk-breadcrumb>*>:hover,.uk-overlay-primary .uk-breadcrumb>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-breadcrumb>:last-child>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>:last-child>*,.uk-card-secondary.uk-card-body .uk-breadcrumb>:last-child>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>:last-child>*,.uk-light .uk-breadcrumb>:last-child>*,.uk-offcanvas-bar .uk-breadcrumb>:last-child>*,.uk-overlay-primary .uk-breadcrumb>:last-child>*,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-light .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-offcanvas-bar .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-overlay-primary .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-pagination>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>*,.uk-card-secondary.uk-card-body .uk-pagination>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>*,.uk-light .uk-pagination>*>*,.uk-offcanvas-bar .uk-pagination>*>*,.uk-overlay-primary .uk-pagination>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-pagination>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>:hover,.uk-card-secondary.uk-card-body .uk-pagination>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>:hover,.uk-light .uk-pagination>*>:hover,.uk-offcanvas-bar .uk-pagination>*>:hover,.uk-overlay-primary .uk-pagination>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-pagination>.uk-active>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>.uk-active>*,.uk-card-secondary.uk-card-body .uk-pagination>.uk-active>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>.uk-active>*,.uk-light .uk-pagination>.uk-active>*,.uk-offcanvas-bar .uk-pagination>.uk-active>*,.uk-overlay-primary .uk-pagination>.uk-active>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>.uk-active>*{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-pagination>.uk-disabled>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>.uk-disabled>*,.uk-card-secondary.uk-card-body .uk-pagination>.uk-disabled>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>.uk-disabled>*,.uk-light .uk-pagination>.uk-disabled>*,.uk-offcanvas-bar .uk-pagination>.uk-disabled>*,.uk-overlay-primary .uk-pagination>.uk-disabled>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-tab::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab::before,.uk-card-secondary.uk-card-body .uk-tab::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab::before,.uk-light .uk-tab::before,.uk-offcanvas-bar .uk-tab::before,.uk-overlay-primary .uk-tab::before,.uk-section-primary:not(.uk-preserve-color) .uk-tab::before,.uk-section-secondary:not(.uk-preserve-color) .uk-tab::before,.uk-tile-primary:not(.uk-preserve-color) .uk-tab::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab::before{border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-tab>*>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a,.uk-card-secondary.uk-card-body .uk-tab>*>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a,.uk-light .uk-tab>*>a,.uk-offcanvas-bar .uk-tab>*>a,.uk-overlay-primary .uk-tab>*>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-tab>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a:hover,.uk-card-secondary.uk-card-body .uk-tab>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a:hover,.uk-light .uk-tab>*>a:hover,.uk-offcanvas-bar .uk-tab>*>a:hover,.uk-overlay-primary .uk-tab>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-tab>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>.uk-active>a,.uk-card-secondary.uk-card-body .uk-tab>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>.uk-active>a,.uk-light .uk-tab>.uk-active>a,.uk-offcanvas-bar .uk-tab>.uk-active>a,.uk-overlay-primary .uk-tab>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>.uk-active>a{color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-tab>.uk-disabled>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>.uk-disabled>a,.uk-card-secondary.uk-card-body .uk-tab>.uk-disabled>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>.uk-disabled>a,.uk-light .uk-tab>.uk-disabled>a,.uk-offcanvas-bar .uk-tab>.uk-disabled>a,.uk-overlay-primary .uk-tab>.uk-disabled>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-slidenav,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav,.uk-card-secondary.uk-card-body .uk-slidenav,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav,.uk-light .uk-slidenav,.uk-offcanvas-bar .uk-slidenav,.uk-overlay-primary .uk-slidenav,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-slidenav:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:hover,.uk-card-secondary.uk-card-body .uk-slidenav:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:hover,.uk-light .uk-slidenav:hover,.uk-offcanvas-bar .uk-slidenav:hover,.uk-overlay-primary .uk-slidenav:hover,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:hover{color:rgba(255,255,255,.95)}.uk-card-primary.uk-card-body .uk-slidenav:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:active,.uk-card-secondary.uk-card-body .uk-slidenav:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:active,.uk-light .uk-slidenav:active,.uk-offcanvas-bar .uk-slidenav:active,.uk-overlay-primary .uk-slidenav:active,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:active,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:active,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:active{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-dotnav>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>*,.uk-card-secondary.uk-card-body .uk-dotnav>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>*,.uk-light .uk-dotnav>*>*,.uk-offcanvas-bar .uk-dotnav>*>*,.uk-overlay-primary .uk-dotnav>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>*{background-color:transparent;border-color:rgba(255,255,255,.9)}.uk-card-primary.uk-card-body .uk-dotnav>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:hover,.uk-card-secondary.uk-card-body .uk-dotnav>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:hover,.uk-light .uk-dotnav>*>:hover,.uk-offcanvas-bar .uk-dotnav>*>:hover,.uk-overlay-primary .uk-dotnav>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:hover{background-color:rgba(255,255,255,.9);border-color:transparent}.uk-card-primary.uk-card-body .uk-dotnav>*>:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:active,.uk-card-secondary.uk-card-body .uk-dotnav>*>:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:active,.uk-light .uk-dotnav>*>:active,.uk-offcanvas-bar .uk-dotnav>*>:active,.uk-overlay-primary .uk-dotnav>*>:active,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:active{background-color:rgba(255,255,255,.5);border-color:transparent}.uk-card-primary.uk-card-body .uk-dotnav>.uk-active>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>.uk-active>*,.uk-card-secondary.uk-card-body .uk-dotnav>.uk-active>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>.uk-active>*,.uk-light .uk-dotnav>.uk-active>*,.uk-offcanvas-bar .uk-dotnav>.uk-active>*,.uk-overlay-primary .uk-dotnav>.uk-active>*,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*{background-color:rgba(255,255,255,.9);border-color:transparent}.uk-card-primary.uk-card-body .uk-text-lead,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-lead,.uk-card-secondary.uk-card-body .uk-text-lead,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-lead,.uk-light .uk-text-lead,.uk-offcanvas-bar .uk-text-lead,.uk-overlay-primary .uk-text-lead,.uk-section-primary:not(.uk-preserve-color) .uk-text-lead,.uk-section-secondary:not(.uk-preserve-color) .uk-text-lead,.uk-tile-primary:not(.uk-preserve-color) .uk-text-lead,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-lead{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-text-meta,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-meta,.uk-card-secondary.uk-card-body .uk-text-meta,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-meta,.uk-light .uk-text-meta,.uk-offcanvas-bar .uk-text-meta,.uk-overlay-primary .uk-text-meta,.uk-section-primary:not(.uk-preserve-color) .uk-text-meta,.uk-section-secondary:not(.uk-preserve-color) .uk-text-meta,.uk-tile-primary:not(.uk-preserve-color) .uk-text-meta,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-meta{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-text-muted,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-muted,.uk-card-secondary.uk-card-body .uk-text-muted,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-muted,.uk-light .uk-text-muted,.uk-offcanvas-bar .uk-text-muted,.uk-overlay-primary .uk-text-muted,.uk-section-primary:not(.uk-preserve-color) .uk-text-muted,.uk-section-secondary:not(.uk-preserve-color) .uk-text-muted,.uk-tile-primary:not(.uk-preserve-color) .uk-text-muted,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-muted{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-text-emphasis,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-emphasis,.uk-card-secondary.uk-card-body .uk-text-emphasis,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-emphasis,.uk-light .uk-text-emphasis,.uk-offcanvas-bar .uk-text-emphasis,.uk-overlay-primary .uk-text-emphasis,.uk-section-primary:not(.uk-preserve-color) .uk-text-emphasis,.uk-section-secondary:not(.uk-preserve-color) .uk-text-emphasis,.uk-tile-primary:not(.uk-preserve-color) .uk-text-emphasis,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-emphasis{color:#fff!important}.uk-card-primary.uk-card-body .uk-text-primary,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-primary,.uk-card-secondary.uk-card-body .uk-text-primary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-primary,.uk-light .uk-text-primary,.uk-offcanvas-bar .uk-text-primary,.uk-overlay-primary .uk-text-primary,.uk-section-primary:not(.uk-preserve-color) .uk-text-primary,.uk-section-secondary:not(.uk-preserve-color) .uk-text-primary,.uk-tile-primary:not(.uk-preserve-color) .uk-text-primary,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-primary{color:#fff!important}.uk-card-primary.uk-card-body .uk-text-secondary,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-secondary,.uk-card-secondary.uk-card-body .uk-text-secondary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-secondary,.uk-light .uk-text-secondary,.uk-offcanvas-bar .uk-text-secondary,.uk-overlay-primary .uk-text-secondary,.uk-section-primary:not(.uk-preserve-color) .uk-text-secondary,.uk-section-secondary:not(.uk-preserve-color) .uk-text-secondary,.uk-tile-primary:not(.uk-preserve-color) .uk-text-secondary,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-secondary{color:#fff!important}.uk-card-primary.uk-card-body .uk-column-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-column-divider,.uk-card-secondary.uk-card-body .uk-column-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-column-divider,.uk-light .uk-column-divider,.uk-offcanvas-bar .uk-column-divider,.uk-overlay-primary .uk-column-divider,.uk-section-primary:not(.uk-preserve-color) .uk-column-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-column-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-column-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-column-divider{column-rule-color:rgba(255,255,255,0.2)}.uk-card-primary.uk-card-body .uk-logo,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo,.uk-card-secondary.uk-card-body .uk-logo,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo,.uk-light .uk-logo,.uk-offcanvas-bar .uk-logo,.uk-overlay-primary .uk-logo,.uk-section-primary:not(.uk-preserve-color) .uk-logo,.uk-section-secondary:not(.uk-preserve-color) .uk-logo,.uk-tile-primary:not(.uk-preserve-color) .uk-logo,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo{color:#fff}.uk-card-primary.uk-card-body .uk-logo:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo:hover,.uk-card-secondary.uk-card-body .uk-logo:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo:hover,.uk-light .uk-logo:hover,.uk-offcanvas-bar .uk-logo:hover,.uk-overlay-primary .uk-logo:hover,.uk-section-primary:not(.uk-preserve-color) .uk-logo:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-logo:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-logo:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo:hover{color:#fff}.uk-card-primary.uk-card-body .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-card-primary>:not([class*=uk-card-media]) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-card-secondary.uk-card-body .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-light .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-offcanvas-bar .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-overlay-primary .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-section-primary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-section-secondary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-tile-primary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-tile-secondary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse){display:none}.uk-card-primary.uk-card-body .uk-logo-inverse,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo-inverse,.uk-card-secondary.uk-card-body .uk-logo-inverse,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo-inverse,.uk-light .uk-logo-inverse,.uk-offcanvas-bar .uk-logo-inverse,.uk-overlay-primary .uk-logo-inverse,.uk-section-primary:not(.uk-preserve-color) .uk-logo-inverse,.uk-section-secondary:not(.uk-preserve-color) .uk-logo-inverse,.uk-tile-primary:not(.uk-preserve-color) .uk-logo-inverse,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo-inverse{display:block}.uk-card-primary.uk-card-body .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-primary.uk-card-body .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-card-secondary.uk-card-body .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-secondary.uk-card-body .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-light .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-light .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-offcanvas-bar .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-offcanvas-bar .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-overlay-primary .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-overlay-primary .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-section-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-section-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-accordion-title::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title::before,.uk-card-secondary.uk-card-body .uk-accordion-title::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title::before,.uk-light .uk-accordion-title::before,.uk-offcanvas-bar .uk-accordion-title::before,.uk-overlay-primary .uk-accordion-title::before,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-open>.uk-accordion-title::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-open>.uk-accordion-title::before,.uk-card-secondary.uk-card-body .uk-open>.uk-accordion-title::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-open>.uk-accordion-title::before,.uk-light .uk-open>.uk-accordion-title::before,.uk-offcanvas-bar .uk-open>.uk-accordion-title::before,.uk-overlay-primary .uk-open>.uk-accordion-title::before,.uk-section-primary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-section-secondary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-tile-primary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E")}*{--uk-inverse:initial}.uk-card-primary.uk-card-body,.uk-card-primary>:not([class*=uk-card-media]),.uk-card-secondary.uk-card-body,.uk-card-secondary>:not([class*=uk-card-media]),.uk-light,.uk-offcanvas-bar,.uk-overlay-primary,.uk-section-primary:not(.uk-preserve-color),.uk-section-secondary:not(.uk-preserve-color),.uk-tile-primary:not(.uk-preserve-color),.uk-tile-secondary:not(.uk-preserve-color){--uk-inverse:light}.uk-card-default.uk-card-body,.uk-card-default>:not([class*=uk-card-media]),.uk-dark,.uk-dropbar,.uk-dropdown,.uk-navbar-container:not(.uk-navbar-transparent),.uk-navbar-dropdown,.uk-overlay-default,.uk-section-default:not(.uk-preserve-color),.uk-section-muted:not(.uk-preserve-color),.uk-tile-default:not(.uk-preserve-color),.uk-tile-muted:not(.uk-preserve-color){--uk-inverse:dark}.uk-inverse-light{--uk-inverse:light!important}.uk-inverse-dark{--uk-inverse:dark!important}@media print{*,::after,::before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}} \ No newline at end of file diff --git a/web/static/uikit/css/uikit.min.css b/web/static/uikit/css/uikit.min.css new file mode 100644 index 0000000000000000000000000000000000000000..c5e41971902ae5f1661e6e38c44db0ee11eb9f67 --- /dev/null +++ b/web/static/uikit/css/uikit.min.css @@ -0,0 +1 @@ +/*! UIkit 3.23.12 | https://www.getuikit.com | (c) 2014 - 2025 YOOtheme | MIT License */html{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:16px;font-weight:400;line-height:1.5;-webkit-text-size-adjust:100%;background:#fff;color:#666}body{margin:0}.uk-link,a{color:#1e87f0;text-decoration:none;cursor:pointer}.uk-link-toggle:hover .uk-link,.uk-link:hover,a:hover{color:#0f6ecd;text-decoration:underline}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration-style:dotted}b,strong{font-weight:bolder}:not(pre)>code,:not(pre)>kbd,:not(pre)>samp{font-family:Consolas,monaco,monospace;font-size:.875rem;color:#f0506e;white-space:nowrap;padding:2px 6px;background:#f8f8f8}em{color:#f0506e}ins{background:#ffd;color:#666;text-decoration:none}mark{background:#ffd;color:#666}q{font-style:italic}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}audio,canvas,iframe,img,svg,video{vertical-align:middle}canvas,img,svg,video{max-width:100%;height:auto;box-sizing:border-box}img:not([src]){visibility:hidden;min-width:1px}iframe{border:0}address,dl,fieldset,figure,ol,p,pre,ul{margin:0 0 20px 0}*+address,*+dl,*+fieldset,*+figure,*+ol,*+p,*+pre,*+ul{margin-top:20px}.uk-h1,.uk-h2,.uk-h3,.uk-h4,.uk-h5,.uk-h6,.uk-heading-2xlarge,.uk-heading-3xlarge,.uk-heading-large,.uk-heading-medium,.uk-heading-small,.uk-heading-xlarge,h1,h2,h3,h4,h5,h6{margin:0 0 20px 0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-weight:400;color:#333;text-transform:none}*+.uk-h1,*+.uk-h2,*+.uk-h3,*+.uk-h4,*+.uk-h5,*+.uk-h6,*+.uk-heading-2xlarge,*+.uk-heading-3xlarge,*+.uk-heading-large,*+.uk-heading-medium,*+.uk-heading-small,*+.uk-heading-xlarge,*+h1,*+h2,*+h3,*+h4,*+h5,*+h6{margin-top:40px}.uk-h1,h1{font-size:2.23125rem;line-height:1.2}.uk-h2,h2{font-size:1.7rem;line-height:1.3}.uk-h3,h3{font-size:1.5rem;line-height:1.4}.uk-h4,h4{font-size:1.25rem;line-height:1.4}.uk-h5,h5{font-size:16px;line-height:1.4}.uk-h6,h6{font-size:.875rem;line-height:1.4}@media (min-width:960px){.uk-h1,h1{font-size:2.625rem}.uk-h2,h2{font-size:2rem}}ol,ul{padding-left:30px}ol>li>ol,ol>li>ul,ul>li>ol,ul>li>ul{margin:0}dt{font-weight:700}dd{margin-left:0}.uk-hr,hr{overflow:visible;text-align:inherit;margin:0 0 20px 0;border:0;border-top:1px solid #e5e5e5}*+.uk-hr,*+hr{margin-top:20px}address{font-style:normal}blockquote{margin:0 0 20px 0;font-size:1.25rem;line-height:1.5;font-style:italic;color:#333}*+blockquote{margin-top:20px}blockquote p:last-of-type{margin-bottom:0}blockquote footer{margin-top:10px;font-size:.875rem;line-height:1.5;color:#666}blockquote footer::before{content:"— "}pre{font:0.875rem/1.5 Consolas,monaco,monospace;color:#666;-moz-tab-size:4;tab-size:4;overflow:auto;padding:10px;border:1px solid #e5e5e5;border-radius:3px;background:#fff}pre code{font-family:Consolas,monaco,monospace}:focus{outline:0}:focus-visible{outline:2px dotted #333}::selection{background:#39f;color:#fff;text-shadow:none}details,main{display:block}summary{display:list-item}template{display:none}:root{--uk-breakpoint-s:640px;--uk-breakpoint-m:960px;--uk-breakpoint-l:1200px;--uk-breakpoint-xl:1600px}.uk-link-muted a,.uk-link-toggle .uk-link-muted,a.uk-link-muted{color:#999}.uk-link-muted a:hover,.uk-link-toggle:hover .uk-link-muted,a.uk-link-muted:hover{color:#666}.uk-link-text a,.uk-link-toggle .uk-link-text,a.uk-link-text{color:inherit}.uk-link-text a:hover,.uk-link-toggle:hover .uk-link-text,a.uk-link-text:hover{color:#999}.uk-link-heading a,.uk-link-toggle .uk-link-heading,a.uk-link-heading{color:inherit}.uk-link-heading a:hover,.uk-link-toggle:hover .uk-link-heading,a.uk-link-heading:hover{color:#1e87f0;text-decoration:none}.uk-link-reset a,a.uk-link-reset{color:inherit!important;text-decoration:none!important}.uk-link-toggle{color:inherit!important;text-decoration:none!important}.uk-heading-small{font-size:2.6rem;line-height:1.2}.uk-heading-medium{font-size:2.8875rem;line-height:1.1}.uk-heading-large{font-size:3.4rem;line-height:1.1}.uk-heading-xlarge{font-size:4rem;line-height:1}.uk-heading-2xlarge{font-size:6rem;line-height:1}.uk-heading-3xlarge{font-size:8rem;line-height:1}@media (min-width:960px){.uk-heading-small{font-size:3.25rem}.uk-heading-medium{font-size:3.5rem}.uk-heading-large{font-size:4rem}.uk-heading-xlarge{font-size:6rem}.uk-heading-2xlarge{font-size:8rem}.uk-heading-3xlarge{font-size:11rem}}@media (min-width:1200px){.uk-heading-medium{font-size:4rem}.uk-heading-large{font-size:6rem}.uk-heading-xlarge{font-size:8rem}.uk-heading-2xlarge{font-size:11rem}.uk-heading-3xlarge{font-size:15rem}}.uk-heading-divider{padding-bottom:calc(5px + .1em);border-bottom:calc(.2px + .05em) solid #e5e5e5}.uk-heading-bullet{position:relative}.uk-heading-bullet::before{content:"";display:inline-block;position:relative;top:calc(-.1 * 1em);vertical-align:middle;height:calc(4px + .7em);margin-right:calc(5px + .2em);border-left:calc(5px + .1em) solid #e5e5e5}.uk-heading-line{overflow:hidden}.uk-heading-line>*{display:inline-block;position:relative}.uk-heading-line>::after,.uk-heading-line>::before{content:"";position:absolute;top:calc(50% - (calc(.2px + .05em)/ 2));width:2000px;border-bottom:calc(.2px + .05em) solid #e5e5e5}.uk-heading-line>::before{right:100%;margin-right:calc(5px + .3em)}.uk-heading-line>::after{left:100%;margin-left:calc(5px + .3em)}[class*=uk-divider]{border:none;margin-bottom:20px}*+[class*=uk-divider]{margin-top:20px}.uk-divider-icon{position:relative;height:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22%23e5e5e5%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:50% 50%}.uk-divider-icon::after,.uk-divider-icon::before{content:"";position:absolute;top:50%;max-width:calc(50% - (50px / 2));border-bottom:1px solid #e5e5e5}.uk-divider-icon::before{right:calc(50% + (50px / 2));width:100%}.uk-divider-icon::after{left:calc(50% + (50px / 2));width:100%}.uk-divider-small{line-height:0}.uk-divider-small::after{content:"";display:inline-block;width:100px;max-width:100%;border-top:1px solid #e5e5e5;vertical-align:top}.uk-divider-vertical{width:max-content;height:100px;margin-left:auto;margin-right:auto;border-left:1px solid #e5e5e5}.uk-list{padding:0;list-style:none}.uk-list>*{break-inside:avoid-column}.uk-list>*>:last-child{margin-bottom:0}.uk-list>*>ul,.uk-list>:nth-child(n+2){margin-top:10px}.uk-list-circle,.uk-list-decimal,.uk-list-disc,.uk-list-hyphen,.uk-list-square{padding-left:30px}.uk-list-disc{list-style-type:disc}.uk-list-circle{list-style-type:circle}.uk-list-square{list-style-type:square}.uk-list-decimal{list-style-type:decimal}.uk-list-hyphen{list-style-type:'– '}.uk-list-muted>::marker{color:#999!important}.uk-list-emphasis>::marker{color:#333!important}.uk-list-primary>::marker{color:#1e87f0!important}.uk-list-secondary>::marker{color:#222!important}.uk-list-bullet>*{position:relative;padding-left:30px}.uk-list-bullet>::before{content:"";position:absolute;top:0;left:0;width:30px;height:1.5em;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-list-divider>:nth-child(n+2){margin-top:10px;padding-top:10px;border-top:1px solid #e5e5e5}.uk-list-striped>*{padding:10px 10px}.uk-list-striped>:nth-of-type(odd){border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.uk-list-striped>:nth-of-type(odd){background:#f8f8f8}.uk-list-striped>:nth-child(n+2){margin-top:0}.uk-list-large>*>ul,.uk-list-large>:nth-child(n+2){margin-top:20px}.uk-list-collapse>*>ul,.uk-list-collapse>:nth-child(n+2){margin-top:0}.uk-list-large.uk-list-divider>:nth-child(n+2){margin-top:20px;padding-top:20px}.uk-list-collapse.uk-list-divider>:nth-child(n+2){margin-top:0;padding-top:0}.uk-list-large.uk-list-striped>*{padding:20px 10px}.uk-list-collapse.uk-list-striped>*{padding-top:0;padding-bottom:0}.uk-list-collapse.uk-list-striped>:nth-child(n+2),.uk-list-large.uk-list-striped>:nth-child(n+2){margin-top:0}.uk-description-list>dt{color:#333;font-size:.875rem;font-weight:400;text-transform:uppercase}.uk-description-list>dt:nth-child(n+2){margin-top:20px}.uk-description-list-divider>dt:nth-child(n+2){margin-top:20px;padding-top:20px;border-top:1px solid #e5e5e5}.uk-table{border-collapse:collapse;border-spacing:0;width:100%;margin-bottom:20px}*+.uk-table{margin-top:20px}.uk-table th{padding:16px 12px;text-align:left;vertical-align:bottom;font-size:.875rem;font-weight:400;color:#999;text-transform:uppercase}.uk-table td{padding:16px 12px;vertical-align:top}.uk-table td>:last-child{margin-bottom:0}.uk-table tfoot{font-size:.875rem}.uk-table caption{font-size:.875rem;text-align:left;color:#999}.uk-table-middle,.uk-table-middle td{vertical-align:middle!important}.uk-table-divider>:first-child>tr:not(:first-child),.uk-table-divider>:not(:first-child)>tr,.uk-table-divider>tr:not(:first-child){border-top:1px solid #e5e5e5}.uk-table-striped tbody tr:nth-of-type(odd),.uk-table-striped>tr:nth-of-type(odd){background:#f8f8f8;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.uk-table-hover tbody tr:hover,.uk-table-hover>tr:hover{background:#ffd}.uk-table tbody tr.uk-active,.uk-table>tr.uk-active{background:#ffd}.uk-table-small td,.uk-table-small th{padding:10px 12px}.uk-table-large td,.uk-table-large th{padding:22px 12px}.uk-table-justify td:first-child,.uk-table-justify th:first-child{padding-left:0}.uk-table-justify td:last-child,.uk-table-justify th:last-child{padding-right:0}.uk-table-shrink{width:1px}.uk-table-expand{min-width:150px}.uk-table-link{padding:0!important}.uk-table-link>a{display:block;padding:16px 12px}.uk-table-small .uk-table-link>a{padding:10px 12px}@media (max-width:959px){.uk-table-responsive,.uk-table-responsive tbody,.uk-table-responsive td,.uk-table-responsive th,.uk-table-responsive tr{display:block}.uk-table-responsive thead{display:none}.uk-table-responsive td,.uk-table-responsive th{width:auto!important;max-width:none!important;min-width:0!important;overflow:visible!important;white-space:normal!important}.uk-table-responsive .uk-table-link:not(:first-child)>a,.uk-table-responsive td:not(:first-child):not(.uk-table-link),.uk-table-responsive th:not(:first-child):not(.uk-table-link){padding-top:5px!important}.uk-table-responsive .uk-table-link:not(:last-child)>a,.uk-table-responsive td:not(:last-child):not(.uk-table-link),.uk-table-responsive th:not(:last-child):not(.uk-table-link){padding-bottom:5px!important}.uk-table-justify.uk-table-responsive td,.uk-table-justify.uk-table-responsive th{padding-left:0;padding-right:0}}.uk-table tbody tr{transition:background-color .1s linear}.uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-table-striped>tr:nth-of-type(2n):last-child{border-bottom:1px solid #e5e5e5}.uk-icon{margin:0;border:none;border-radius:0;overflow:visible;font:inherit;color:inherit;text-transform:none;padding:0;background-color:transparent;display:inline-block;fill:currentcolor;line-height:0}button.uk-icon:not(:disabled){cursor:pointer}.uk-icon::-moz-focus-inner{border:0;padding:0}.uk-icon:not(.uk-preserve) [fill*="#"]:not(.uk-preserve){fill:currentcolor}.uk-icon:not(.uk-preserve) [stroke*="#"]:not(.uk-preserve){stroke:currentcolor}.uk-icon>*{transform:translate(0,0)}.uk-icon-image{width:20px;height:20px;background-position:50% 50%;background-repeat:no-repeat;background-size:contain;vertical-align:middle;object-fit:scale-down;max-width:none}.uk-icon-link{color:#999;text-decoration:none!important}.uk-icon-link:hover{color:#666}.uk-active>.uk-icon-link,.uk-icon-link:active{color:#595959}.uk-icon-button{box-sizing:border-box;width:36px;height:36px;border-radius:500px;background:#f8f8f8;color:#999;vertical-align:middle;display:inline-flex;justify-content:center;align-items:center;transition:.1s ease-in-out;transition-property:color,background-color}.uk-icon-button:hover{background-color:#ebebeb;color:#666}.uk-active>.uk-icon-button,.uk-icon-button:active{background-color:#dfdfdf;color:#666}.uk-range{-webkit-appearance:none;box-sizing:border-box;margin:0;vertical-align:middle;max-width:100%;width:100%;background:0 0}.uk-range:focus{outline:0}.uk-range::-moz-focus-outer{border:none}.uk-range:not(:disabled)::-webkit-slider-thumb{cursor:pointer}.uk-range:not(:disabled)::-moz-range-thumb{cursor:pointer}.uk-range::-webkit-slider-runnable-track{height:3px;background:#ebebeb;border-radius:500px}.uk-range:active::-webkit-slider-runnable-track,.uk-range:focus::-webkit-slider-runnable-track{background:#dedede}.uk-range::-moz-range-track{height:3px;background:#ebebeb;border-radius:500px}.uk-range:focus::-moz-range-track{background:#dedede}.uk-range::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-7px;height:15px;width:15px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-range::-moz-range-thumb{border:none;height:15px;width:15px;margin-top:-7px;border-radius:500px;background:#fff;border:1px solid #ccc}.uk-checkbox,.uk-input,.uk-radio,.uk-select,.uk-textarea{box-sizing:border-box;margin:0;border-radius:0;font:inherit}.uk-input{overflow:visible}.uk-select{text-transform:none}.uk-select optgroup{font:inherit;font-weight:700}.uk-textarea{overflow:auto}.uk-input[type=search]::-webkit-search-cancel-button,.uk-input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.uk-input[type=number]::-webkit-inner-spin-button,.uk-input[type=number]::-webkit-outer-spin-button{height:auto}.uk-input[type=date]::-webkit-datetime-edit,.uk-input[type=datetime-local]::-webkit-datetime-edit,.uk-input[type=time]::-webkit-datetime-edit{display:inline-flex;align-items:center;height:100%;padding:0}.uk-input::-moz-placeholder,.uk-textarea::-moz-placeholder{opacity:1}.uk-checkbox:not(:disabled),.uk-radio:not(:disabled){cursor:pointer}.uk-fieldset{border:none;margin:0;padding:0;min-width:0}.uk-input,.uk-textarea{-webkit-appearance:none}.uk-input,.uk-select,.uk-textarea{max-width:100%;width:100%;border:0 none;padding:0 10px;background:#fff;color:#666;border:1px solid #e5e5e5;transition:.2s ease-in-out;transition-property:color,background-color,border}.uk-input,.uk-select:not([multiple]):not([size]){height:40px;vertical-align:middle;display:inline-block}.uk-input:not(input),.uk-select:not(select){line-height:38px}.uk-select[multiple],.uk-select[size],.uk-textarea{padding-top:6px;padding-bottom:6px;vertical-align:top}.uk-select[multiple],.uk-select[size]{resize:vertical}.uk-input:focus,.uk-select:focus,.uk-textarea:focus{outline:0;background-color:#fff;color:#666;border-color:#1e87f0}.uk-input:disabled,.uk-select:disabled,.uk-textarea:disabled{background-color:#f8f8f8;color:#999;border-color:#e5e5e5}.uk-input::placeholder{color:#999}.uk-textarea::placeholder{color:#999}.uk-form-small{font-size:.875rem}.uk-form-small:not(textarea):not([multiple]):not([size]){height:30px;padding-left:8px;padding-right:8px}[multiple].uk-form-small,[size].uk-form-small,textarea.uk-form-small{padding:5px 8px}.uk-form-small:not(select):not(input):not(textarea){line-height:28px}.uk-form-large{font-size:1.25rem}.uk-form-large:not(textarea):not([multiple]):not([size]){height:55px;padding-left:12px;padding-right:12px}[multiple].uk-form-large,[size].uk-form-large,textarea.uk-form-large{padding:7px 12px}.uk-form-large:not(select):not(input):not(textarea){line-height:53px}.uk-form-danger,.uk-form-danger:focus{color:#f0506e;border-color:#f0506e}.uk-form-success,.uk-form-success:focus{color:#32d296;border-color:#32d296}.uk-form-blank{background:0 0;border-color:transparent}.uk-form-blank:focus{border-color:#e5e5e5;border-style:solid}input.uk-form-width-xsmall{width:50px}select.uk-form-width-xsmall{width:75px}.uk-form-width-small{width:130px}.uk-form-width-medium{width:200px}.uk-form-width-large{width:500px}.uk-select:not([multiple]):not([size]){-webkit-appearance:none;-moz-appearance:none;padding-right:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:100% 50%}.uk-select:not([multiple]):not([size]) option{color:#666}.uk-select:not([multiple]):not([size]):disabled{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-input[list]{padding-right:20px;background-repeat:no-repeat;background-position:100% 50%}.uk-input[list]:focus,.uk-input[list]:hover{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-input[list]::-webkit-calendar-picker-indicator{display:none!important}.uk-checkbox,.uk-radio{display:inline-block;height:16px;width:16px;overflow:hidden;margin-top:-4px;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;border:1px solid #ccc;transition:.2s ease-in-out;transition-property:background-color,border}.uk-radio{border-radius:50%}.uk-checkbox:focus,.uk-radio:focus{background-color:rgba(0,0,0,0);outline:0;border-color:#1e87f0}.uk-checkbox:checked,.uk-checkbox:indeterminate,.uk-radio:checked{background-color:#1e87f0;border-color:transparent}.uk-checkbox:checked:focus,.uk-checkbox:indeterminate:focus,.uk-radio:checked:focus{background-color:#0e6dcd}.uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23fff%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23fff%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23fff%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled,.uk-radio:disabled{background-color:#f8f8f8;border-color:#e5e5e5}.uk-radio:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23999%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23999%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:disabled:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23999%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-legend{width:100%;color:inherit;padding:0;font-size:1.5rem;line-height:1.4}.uk-form-custom{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-form-custom input[type=file],.uk-form-custom select{position:absolute;top:0;z-index:1;width:100%;height:100%;left:0;-webkit-appearance:none;opacity:0;cursor:pointer}.uk-form-custom input[type=file]{font-size:500px;overflow:hidden}.uk-form-label{color:#333;font-size:.875rem}.uk-form-stacked .uk-form-label{display:block;margin-bottom:5px}@media (max-width:959px){.uk-form-horizontal .uk-form-label{display:block;margin-bottom:5px}}@media (min-width:960px){.uk-form-horizontal .uk-form-label{width:200px;margin-top:7px;float:left}.uk-form-horizontal .uk-form-controls{margin-left:215px}.uk-form-horizontal .uk-form-controls-text{padding-top:7px}}.uk-form-icon{position:absolute;top:0;bottom:0;left:0;width:40px;display:inline-flex;justify-content:center;align-items:center;color:#999}.uk-form-icon:hover{color:#666}.uk-form-icon:not(a):not(button):not(input){pointer-events:none}.uk-form-icon:not(.uk-form-icon-flip)~.uk-input{padding-left:40px!important}.uk-form-icon-flip{right:0;left:auto}.uk-form-icon-flip~.uk-input{padding-right:40px!important}.uk-button{margin:0;border:none;overflow:visible;font:inherit;color:inherit;text-transform:none;-webkit-appearance:none;border-radius:0;display:inline-block;box-sizing:border-box;padding:0 30px;vertical-align:middle;font-size:.875rem;line-height:38px;text-align:center;text-decoration:none;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color,border-color}.uk-button:not(:disabled){cursor:pointer}.uk-button::-moz-focus-inner{border:0;padding:0}.uk-button:hover{text-decoration:none}.uk-button-default{background-color:transparent;color:#333;border:1px solid #e5e5e5}.uk-button-default:hover{background-color:transparent;color:#333;border-color:#b2b2b2}.uk-button-default.uk-active,.uk-button-default:active{background-color:transparent;color:#333;border-color:#999}.uk-button-primary{background-color:#1e87f0;color:#fff;border:1px solid transparent}.uk-button-primary:hover{background-color:#0f7ae5;color:#fff}.uk-button-primary.uk-active,.uk-button-primary:active{background-color:#0e6dcd;color:#fff}.uk-button-secondary{background-color:#222;color:#fff;border:1px solid transparent}.uk-button-secondary:hover{background-color:#151515;color:#fff}.uk-button-secondary.uk-active,.uk-button-secondary:active{background-color:#080808;color:#fff}.uk-button-danger{background-color:#f0506e;color:#fff;border:1px solid transparent}.uk-button-danger:hover{background-color:#ee395b;color:#fff}.uk-button-danger.uk-active,.uk-button-danger:active{background-color:#ec2147;color:#fff}.uk-button-danger:disabled,.uk-button-default:disabled,.uk-button-primary:disabled,.uk-button-secondary:disabled{background-color:transparent;color:#999;border-color:#e5e5e5}.uk-button-small{padding:0 15px;line-height:28px;font-size:.875rem}.uk-button-large{padding:0 40px;line-height:53px;font-size:.875rem}.uk-button-text{padding:0;line-height:1.5;background:0 0;color:#333;position:relative}.uk-button-text::before{content:"";position:absolute;bottom:0;left:0;right:100%;border-bottom:1px solid currentColor;transition:right .3s ease-out}.uk-button-text:hover{color:#333}.uk-button-text:hover::before{right:0}.uk-button-text:disabled{color:#999}.uk-button-text:disabled::before{display:none}.uk-button-link{padding:0;line-height:1.5;background:0 0;color:#333}.uk-button-link:hover{color:#999;text-decoration:none}.uk-button-link:disabled{color:#999;text-decoration:none}.uk-button-group{display:inline-flex;vertical-align:middle;position:relative}.uk-button-group>.uk-button:nth-child(n+2),.uk-button-group>div:nth-child(n+2) .uk-button{margin-left:-1px}.uk-button-group .uk-button.uk-active,.uk-button-group .uk-button:active,.uk-button-group .uk-button:focus,.uk-button-group .uk-button:hover{position:relative;z-index:1}.uk-progress{vertical-align:baseline;display:block;width:100%;border:0;background-color:#f8f8f8;margin-bottom:20px;height:15px;border-radius:500px;overflow:hidden}*+.uk-progress{margin-top:20px}.uk-progress::-webkit-progress-bar{background-color:transparent}.uk-progress::-webkit-progress-value{background-color:#1e87f0;transition:width .6s ease}.uk-progress::-moz-progress-bar{background-color:#1e87f0;transition:width .6s ease}.uk-section{display:flow-root;box-sizing:border-box;padding-top:40px;padding-bottom:40px}@media (min-width:960px){.uk-section{padding-top:70px;padding-bottom:70px}}.uk-section>:last-child{margin-bottom:0}.uk-section-xsmall{padding-top:20px;padding-bottom:20px}.uk-section-small{padding-top:40px;padding-bottom:40px}.uk-section-large{padding-top:70px;padding-bottom:70px}@media (min-width:960px){.uk-section-large{padding-top:140px;padding-bottom:140px}}.uk-section-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width:960px){.uk-section-xlarge{padding-top:210px;padding-bottom:210px}}.uk-section-default{--uk-inverse:dark;background:#fff}.uk-section-muted{--uk-inverse:dark;background:#f8f8f8}.uk-section-primary{--uk-inverse:light;background:#1e87f0}.uk-section-secondary{--uk-inverse:light;background:#222}.uk-container{display:flow-root;box-sizing:content-box;max-width:1200px;margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px}@media (min-width:640px){.uk-container{padding-left:30px;padding-right:30px}}@media (min-width:960px){.uk-container{padding-left:40px;padding-right:40px}}.uk-container>:last-child{margin-bottom:0}.uk-container .uk-container{padding-left:0;padding-right:0}.uk-container-xsmall{max-width:750px}.uk-container-small{max-width:900px}.uk-container-large{max-width:1400px}.uk-container-xlarge{max-width:1600px}.uk-container-expand{max-width:none}.uk-container-expand-left{margin-left:0}.uk-container-expand-right{margin-right:0}@media (min-width:640px){.uk-container-expand-left.uk-container-xsmall,.uk-container-expand-right.uk-container-xsmall{max-width:calc(50% + (750px / 2) - 30px)}.uk-container-expand-left.uk-container-small,.uk-container-expand-right.uk-container-small{max-width:calc(50% + (900px / 2) - 30px)}}@media (min-width:960px){.uk-container-expand-left,.uk-container-expand-right{max-width:calc(50% + (1200px / 2) - 40px)}.uk-container-expand-left.uk-container-xsmall,.uk-container-expand-right.uk-container-xsmall{max-width:calc(50% + (750px / 2) - 40px)}.uk-container-expand-left.uk-container-small,.uk-container-expand-right.uk-container-small{max-width:calc(50% + (900px / 2) - 40px)}.uk-container-expand-left.uk-container-large,.uk-container-expand-right.uk-container-large{max-width:calc(50% + (1400px / 2) - 40px)}.uk-container-expand-left.uk-container-xlarge,.uk-container-expand-right.uk-container-xlarge{max-width:calc(50% + (1600px / 2) - 40px)}}.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 15px)}.uk-container-item-padding-remove-left{margin-left:-15px}.uk-container-item-padding-remove-right{margin-right:-15px}@media (min-width:640px){.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 30px)}.uk-container-item-padding-remove-left{margin-left:-30px}.uk-container-item-padding-remove-right{margin-right:-30px}}@media (min-width:960px){.uk-container-item-padding-remove-left,.uk-container-item-padding-remove-right{width:calc(100% + 40px)}.uk-container-item-padding-remove-left{margin-left:-40px}.uk-container-item-padding-remove-right{margin-right:-40px}}.uk-tile{display:flow-root;position:relative;box-sizing:border-box;padding-left:15px;padding-right:15px;padding-top:40px;padding-bottom:40px}@media (min-width:640px){.uk-tile{padding-left:30px;padding-right:30px}}@media (min-width:960px){.uk-tile{padding-left:40px;padding-right:40px;padding-top:70px;padding-bottom:70px}}.uk-tile>:last-child{margin-bottom:0}.uk-tile-xsmall{padding-top:20px;padding-bottom:20px}.uk-tile-small{padding-top:40px;padding-bottom:40px}.uk-tile-large{padding-top:70px;padding-bottom:70px}@media (min-width:960px){.uk-tile-large{padding-top:140px;padding-bottom:140px}}.uk-tile-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width:960px){.uk-tile-xlarge{padding-top:210px;padding-bottom:210px}}.uk-tile-default{--uk-inverse:dark;background-color:#fff}.uk-tile-muted{--uk-inverse:dark;background-color:#f8f8f8}.uk-tile-primary{--uk-inverse:light;background-color:#1e87f0}.uk-tile-secondary{--uk-inverse:light;background-color:#222}.uk-card{position:relative;box-sizing:border-box;transition:box-shadow .1s ease-in-out}.uk-card-body{display:flow-root;padding:30px 30px}.uk-card-header{display:flow-root;padding:15px 30px}.uk-card-footer{display:flow-root;padding:15px 30px}@media (min-width:1200px){.uk-card-body{padding:40px 40px}.uk-card-header{padding:20px 40px}.uk-card-footer{padding:20px 40px}}.uk-card-body>:last-child,.uk-card-footer>:last-child,.uk-card-header>:last-child{margin-bottom:0}.uk-card-title{font-size:1.5rem;line-height:1.4}.uk-card-badge{position:absolute;top:15px;right:15px;z-index:1;height:22px;padding:0 10px;background:#1e87f0;color:#fff;font-size:.875rem;display:flex;justify-content:center;align-items:center;line-height:0;border-radius:2px;text-transform:uppercase}.uk-card-badge:first-child+*{margin-top:0}.uk-card-hover:not(.uk-card-default):not(.uk-card-primary):not(.uk-card-secondary):hover{background-color:#fff;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-default{--uk-inverse:dark;background-color:#fff;color:#666;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-default .uk-card-title{color:#333}.uk-card-default.uk-card-hover:hover{background-color:#fff;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-default .uk-card-header{border-bottom:1px solid #e5e5e5}.uk-card-default .uk-card-footer{border-top:1px solid #e5e5e5}.uk-card-primary{--uk-inverse:light;background-color:#1e87f0;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-primary .uk-card-title{color:#fff}.uk-card-primary.uk-card-hover:hover{background-color:#1e87f0;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-secondary{--uk-inverse:light;background-color:#222;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-card-secondary .uk-card-title{color:#fff}.uk-card-secondary.uk-card-hover:hover{background-color:#222;box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-card-small .uk-card-body,.uk-card-small.uk-card-body{padding:20px 20px}.uk-card-small .uk-card-header{padding:13px 20px}.uk-card-small .uk-card-footer{padding:13px 20px}@media (min-width:1200px){.uk-card-large .uk-card-body,.uk-card-large.uk-card-body{padding:70px 70px}.uk-card-large .uk-card-header{padding:35px 70px}.uk-card-large .uk-card-footer{padding:35px 70px}}.uk-card-body>.uk-nav-default{margin-left:-30px;margin-right:-30px}.uk-card-body>.uk-nav-default:only-child{margin-top:-15px;margin-bottom:-15px}.uk-card-body>.uk-nav-default .uk-nav-divider,.uk-card-body>.uk-nav-default .uk-nav-header,.uk-card-body>.uk-nav-default>li>a{padding-left:30px;padding-right:30px}.uk-card-body>.uk-nav-default .uk-nav-sub{padding-left:45px}@media (min-width:1200px){.uk-card-body>.uk-nav-default{margin-left:-40px;margin-right:-40px}.uk-card-body>.uk-nav-default:only-child{margin-top:-25px;margin-bottom:-25px}.uk-card-body>.uk-nav-default .uk-nav-divider,.uk-card-body>.uk-nav-default .uk-nav-header,.uk-card-body>.uk-nav-default>li>a{padding-left:40px;padding-right:40px}.uk-card-body>.uk-nav-default .uk-nav-sub{padding-left:55px}}.uk-card-small>.uk-nav-default{margin-left:-20px;margin-right:-20px}.uk-card-small>.uk-nav-default:only-child{margin-top:-5px;margin-bottom:-5px}.uk-card-small>.uk-nav-default .uk-nav-divider,.uk-card-small>.uk-nav-default .uk-nav-header,.uk-card-small>.uk-nav-default>li>a{padding-left:20px;padding-right:20px}.uk-card-small>.uk-nav-default .uk-nav-sub{padding-left:35px}@media (min-width:1200px){.uk-card-large>.uk-nav-default{margin:0}.uk-card-large>.uk-nav-default:only-child{margin:0}.uk-card-large>.uk-nav-default .uk-nav-divider,.uk-card-large>.uk-nav-default .uk-nav-header,.uk-card-large>.uk-nav-default>li>a{padding-left:0;padding-right:0}.uk-card-large>.uk-nav-default .uk-nav-sub{padding-left:15px}}.uk-close{color:#999;transition:.1s ease-in-out;transition-property:color,opacity}.uk-close:hover{color:#666}.uk-spinner>*{animation:uk-spinner-rotate 1.4s linear infinite}@keyframes uk-spinner-rotate{0%{transform:rotate(0)}100%{transform:rotate(270deg)}}.uk-spinner>*>*{stroke-dasharray:88px;stroke-dashoffset:0;transform-origin:center;animation:uk-spinner-dash 1.4s ease-in-out infinite;stroke-width:1;stroke-linecap:round}@keyframes uk-spinner-dash{0%{stroke-dashoffset:88px}50%{stroke-dashoffset:22px;transform:rotate(135deg)}100%{stroke-dashoffset:88px;transform:rotate(450deg)}}.uk-totop{padding:5px;color:#999;transition:color .1s ease-in-out}.uk-totop:hover{color:#666}.uk-totop:active{color:#333}.uk-marker{padding:5px;background:#222;color:#fff;border-radius:500px}.uk-marker:hover{color:#fff}.uk-alert{position:relative;margin-bottom:20px;padding:15px 29px 15px 15px;background:#f8f8f8;color:#666}*+.uk-alert{margin-top:20px}.uk-alert>:last-child{margin-bottom:0}.uk-alert-close{position:absolute;top:20px;right:15px;color:inherit;opacity:.4}.uk-alert-close:first-child+*{margin-top:0}.uk-alert-close:hover{color:inherit;opacity:.8}.uk-alert-primary{background:#d8eafc;color:#1e87f0}.uk-alert-success{background:#edfbf6;color:#32d296}.uk-alert-warning{background:#fff6ee;color:#faa05a}.uk-alert-danger{background:#fef4f6;color:#f0506e}.uk-alert h1,.uk-alert h2,.uk-alert h3,.uk-alert h4,.uk-alert h5,.uk-alert h6{color:inherit}.uk-alert a:not([class]){color:inherit;text-decoration:underline}.uk-alert a:not([class]):hover{color:inherit;text-decoration:underline}.uk-placeholder{margin-bottom:20px;padding:30px 30px;background:0 0;border:1px dashed #e5e5e5}*+.uk-placeholder{margin-top:20px}.uk-placeholder>:last-child{margin-bottom:0}.uk-badge{box-sizing:border-box;min-width:18px;height:18px;padding:0 5px;border-radius:500px;vertical-align:middle;background:#1e87f0;color:#fff!important;font-size:11px;display:inline-flex;justify-content:center;align-items:center;line-height:0}.uk-badge:hover{text-decoration:none}.uk-label{display:inline-block;padding:0 10px;background:#1e87f0;line-height:1.5;font-size:.875rem;color:#fff;vertical-align:middle;white-space:nowrap;border-radius:2px;text-transform:uppercase}.uk-label-success{background-color:#32d296;color:#fff}.uk-label-warning{background-color:#faa05a;color:#fff}.uk-label-danger{background-color:#f0506e;color:#fff}.uk-overlay{padding:30px 30px}.uk-overlay>:last-child{margin-bottom:0}.uk-overlay-default{--uk-inverse:dark;background:rgba(255,255,255,.8)}.uk-overlay-primary{--uk-inverse:light;background:rgba(34,34,34,.8)}.uk-article{display:flow-root}.uk-article>:last-child{margin-bottom:0}.uk-article+.uk-article{margin-top:70px}.uk-article-title{font-size:2.23125rem;line-height:1.2}@media (min-width:960px){.uk-article-title{font-size:2.625rem}}.uk-article-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-article-meta a{color:#999}.uk-article-meta a:hover{color:#666;text-decoration:none}.uk-comment-body{display:flow-root;overflow-wrap:break-word;word-wrap:break-word}.uk-comment-header{display:flow-root;margin-bottom:20px}.uk-comment-body>:last-child,.uk-comment-header>:last-child{margin-bottom:0}.uk-comment-title{font-size:1.25rem;line-height:1.4}.uk-comment-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-comment-list{padding:0;list-style:none}.uk-comment-list>:nth-child(n+2){margin-top:70px}.uk-comment-list .uk-comment~ul{margin:70px 0 0 0;padding-left:30px;list-style:none}@media (min-width:960px){.uk-comment-list .uk-comment~ul{padding-left:100px}}.uk-comment-list .uk-comment~ul>:nth-child(n+2){margin-top:70px}.uk-comment-primary{padding:30px;background-color:#f8f8f8}.uk-search{display:inline-block;position:relative;max-width:100%;margin:0}.uk-search-input::-webkit-search-cancel-button,.uk-search-input::-webkit-search-decoration{-webkit-appearance:none}.uk-search-input::-moz-placeholder{opacity:1}.uk-search-input{box-sizing:border-box;margin:0;border-radius:0;font:inherit;overflow:visible;-webkit-appearance:none;vertical-align:middle;width:100%;border:none;color:#666}.uk-search-input:focus{outline:0}.uk-search-input::placeholder{color:#999}.uk-search .uk-search-icon{position:absolute;top:0;bottom:0;left:0;display:inline-flex;justify-content:center;align-items:center;color:#999}.uk-search .uk-search-icon:hover{color:#999}.uk-search .uk-search-icon:not(a):not(button):not(input){pointer-events:none}.uk-search .uk-search-icon-flip{right:0;left:auto}.uk-search-default{width:240px}.uk-search-default .uk-search-input{height:40px;padding-left:10px;padding-right:10px;background:0 0;border:1px solid #e5e5e5}.uk-search-default .uk-search-input:focus{background-color:rgba(0,0,0,0);border-color:#1e87f0}.uk-search-default .uk-search-icon{padding-left:10px;padding-right:10px}.uk-search-default:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-left:40px}.uk-search-default:has(.uk-search-icon-flip) .uk-search-input{padding-right:40px}.uk-search-navbar{width:240px}.uk-search-navbar .uk-search-input{height:40px;padding-left:10px;padding-right:10px;background:#fff;border:1px solid #e5e5e5}.uk-search-navbar .uk-search-input:focus{background-color:#fff;border-color:#1e87f0}.uk-search-navbar .uk-search-icon{padding-left:10px;padding-right:10px}.uk-search-navbar:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-left:40px}.uk-search-navbar:has(.uk-search-icon-flip) .uk-search-input{padding-right:40px}.uk-search-medium{width:400px}.uk-search-medium .uk-search-input{height:55px;padding-left:12px;padding-right:12px;background:0 0;font-size:1.5rem;border:1px solid #e5e5e5}.uk-search-medium .uk-search-input:focus{background-color:rgba(0,0,0,0);border-color:#1e87f0}.uk-search-medium .uk-search-icon{padding-left:12px;padding-right:12px}.uk-search-medium:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-left:48px}.uk-search-medium:has(.uk-search-icon-flip) .uk-search-input{padding-right:48px}.uk-search-large{width:500px}.uk-search-large .uk-search-input{height:90px;padding-left:20px;padding-right:20px;background:0 0;font-size:2.625rem;border:1px solid #e5e5e5}.uk-search-large .uk-search-input:focus{background-color:rgba(0,0,0,0);border-color:#1e87f0}.uk-search-large .uk-search-icon{padding-left:20px;padding-right:20px}.uk-search-large:has(.uk-search-icon:not(.uk-search-icon-flip)) .uk-search-input{padding-left:80px}.uk-search-large:has(.uk-search-icon-flip) .uk-search-input{padding-right:80px}.uk-search-toggle{color:#999}.uk-search-toggle:hover{color:#666}.uk-accordion{padding:0;list-style:none}.uk-accordion>:nth-child(n+2){margin-top:20px}.uk-accordion-title{display:block;font-size:1.25rem;line-height:1.4;color:#333;overflow:hidden}.uk-accordion-title::before{content:"";width:1.4em;height:1.4em;margin-left:10px;float:right;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-open>.uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-accordion-title:hover{color:#666;text-decoration:none}.uk-accordion-content{display:flow-root;margin-top:20px}.uk-accordion-content>:last-child{margin-bottom:0}.uk-drop{display:none;position:absolute;z-index:1020;--uk-position-offset:20px;--uk-position-viewport-offset:15px;box-sizing:border-box;width:300px}.uk-drop.uk-open{display:block}.uk-drop-stack .uk-drop-grid>*{width:100%!important}.uk-drop-parent-icon{margin-left:.25em;transition:transform .3s ease-out}[aria-expanded=true]>.uk-drop-parent-icon{transform:rotateX(180deg)}.uk-dropbar{--uk-position-offset:0;--uk-position-shift-offset:0;--uk-position-viewport-offset:0;--uk-inverse:dark;width:auto;padding:25px 15px 25px 15px;background:#fff;color:#666}.uk-dropbar>:last-child{margin-bottom:0}@media (min-width:640px){.uk-dropbar{padding-left:30px;padding-right:30px}}@media (min-width:960px){.uk-dropbar{padding-left:40px;padding-right:40px}}.uk-dropbar :focus-visible{outline-color:#333!important}.uk-dropbar-large{padding-top:40px;padding-bottom:40px}.uk-dropbar-top{box-shadow:0 12px 7px -6px rgba(0,0,0,.05)}.uk-dropbar-bottom{box-shadow:0 -12px 7px -6px rgba(0,0,0,.05)}.uk-dropbar-left{box-shadow:12px 0 7px -6px rgba(0,0,0,.05)}.uk-dropbar-right{box-shadow:-12px 0 7px -6px rgba(0,0,0,.05)}.uk-dropnav-dropbar{position:absolute;z-index:980;padding:0;left:0;right:0}.uk-modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1010;overflow-y:auto;padding:15px 15px;background:rgba(0,0,0,.6);opacity:0;transition:opacity .15s linear}@media (min-width:640px){.uk-modal{padding:50px 30px}}@media (min-width:960px){.uk-modal{padding-left:40px;padding-right:40px}}.uk-modal.uk-open{opacity:1}.uk-modal-page{overflow:hidden}.uk-modal-dialog{position:relative;box-sizing:border-box;margin:0 auto;width:600px;max-width:100%!important;background:#fff;opacity:0;transform:translateY(-100px);transition:.3s linear;transition-property:opacity,transform}.uk-open>.uk-modal-dialog{opacity:1;transform:translateY(0)}.uk-modal-container .uk-modal-dialog{width:1200px}.uk-modal-full{padding:0;background:0 0}.uk-modal-full .uk-modal-dialog{margin:0;width:100%;max-width:100%;transform:translateY(0)}.uk-modal-body{display:flow-root;padding:20px 20px}.uk-modal-header{display:flow-root;padding:10px 20px;background:#fff;border-bottom:1px solid #e5e5e5}.uk-modal-footer{display:flow-root;padding:10px 20px;background:#fff;border-top:1px solid #e5e5e5}@media (min-width:640px){.uk-modal-body{padding:30px 30px}.uk-modal-header{padding:15px 30px}.uk-modal-footer{padding:15px 30px}}.uk-modal-body>:last-child,.uk-modal-footer>:last-child,.uk-modal-header>:last-child{margin-bottom:0}.uk-modal-title{font-size:2rem;line-height:1.3}[class*=uk-modal-close-]{position:absolute;z-index:1010;top:10px;right:10px;padding:5px}[class*=uk-modal-close-]:first-child+*{margin-top:0}.uk-modal-close-outside{top:0;right:-5px;transform:translate(0,-100%);color:#fff}.uk-modal-close-outside:hover{color:#fff}@media (min-width:960px){.uk-modal-close-outside{right:0;transform:translate(100%,-100%)}}.uk-modal-close-full{top:0;right:0;padding:10px;background:#fff}@media (min-width:960px){.uk-modal-close-full{padding:20px}}.uk-slideshow{-webkit-tap-highlight-color:transparent}.uk-slideshow-items{position:relative;z-index:0;margin:0;padding:0;list-style:none;overflow:hidden;-webkit-touch-callout:none;touch-action:pan-y}.uk-slideshow-items>*{position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;will-change:transform,opacity}.uk-slideshow-items>:not(.uk-active){display:none}.uk-slider{-webkit-tap-highlight-color:transparent}.uk-slider-container{overflow:hidden;overflow:clip}.uk-slider-container-offset{margin:-11px -25px -39px -25px;padding:11px 25px 39px 25px}.uk-slider-items{will-change:transform;position:relative;touch-action:pan-y}.uk-slider-items:not(.uk-grid){display:flex;margin:0;padding:0;list-style:none;-webkit-touch-callout:none}.uk-slider-items.uk-grid{flex-wrap:nowrap}.uk-slider-items>*{flex:none!important;box-sizing:border-box;max-width:100%;position:relative}.uk-sticky{position:relative;z-index:980;box-sizing:border-box}.uk-sticky-fixed{margin:0!important}.uk-sticky[class*=uk-animation-]{animation-duration:.2s}.uk-sticky.uk-animation-reverse{animation-duration:.2s}.uk-sticky-placeholder{pointer-events:none}.uk-offcanvas{display:none;position:fixed;top:0;bottom:0;left:0;z-index:1000}.uk-offcanvas-flip .uk-offcanvas{right:0;left:auto}.uk-offcanvas-bar{--uk-inverse:light;position:absolute;top:0;bottom:0;left:-270px;box-sizing:border-box;width:270px;padding:20px 20px;background:#222;overflow-y:auto}@media (min-width:640px){.uk-offcanvas-bar{left:-350px;width:350px;padding:30px 30px}}.uk-offcanvas-flip .uk-offcanvas-bar{left:auto;right:-270px}@media (min-width:640px){.uk-offcanvas-flip .uk-offcanvas-bar{right:-350px}}.uk-open>.uk-offcanvas-bar{left:0}.uk-offcanvas-flip .uk-open>.uk-offcanvas-bar{left:auto;right:0}.uk-offcanvas-bar-animation{transition:left .3s ease-out}.uk-offcanvas-flip .uk-offcanvas-bar-animation{transition-property:right}.uk-offcanvas-reveal{position:absolute;top:0;bottom:0;left:0;width:0;overflow:hidden;transition:width .3s ease-out}.uk-offcanvas-reveal .uk-offcanvas-bar{left:0}.uk-offcanvas-flip .uk-offcanvas-reveal .uk-offcanvas-bar{left:auto;right:0}.uk-open>.uk-offcanvas-reveal{width:270px}@media (min-width:640px){.uk-open>.uk-offcanvas-reveal{width:350px}}.uk-offcanvas-flip .uk-offcanvas-reveal{right:0;left:auto}.uk-offcanvas-close{position:absolute;z-index:1000;top:5px;right:5px;padding:5px}@media (min-width:640px){.uk-offcanvas-close{top:10px;right:10px}}.uk-offcanvas-close:first-child+*{margin-top:0}.uk-offcanvas-overlay{width:100vw;touch-action:none}.uk-offcanvas-overlay::before{content:"";position:absolute;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,.1);opacity:0;transition:opacity .15s linear}.uk-offcanvas-overlay.uk-open::before{opacity:1}.uk-offcanvas-container,.uk-offcanvas-page{overflow-x:hidden;overflow-x:clip}.uk-offcanvas-container{position:relative;left:0;transition:left .3s ease-out;box-sizing:border-box;width:100%}:not(.uk-offcanvas-flip).uk-offcanvas-container-animation{left:270px}.uk-offcanvas-flip.uk-offcanvas-container-animation{left:-270px}@media (min-width:640px){:not(.uk-offcanvas-flip).uk-offcanvas-container-animation{left:350px}.uk-offcanvas-flip.uk-offcanvas-container-animation{left:-350px}}.uk-switcher{margin:0;padding:0;list-style:none}.uk-switcher>:not(.uk-active){display:none}.uk-switcher>*>:last-child{margin-bottom:0}.uk-leader{overflow:hidden}.uk-leader-fill::after{display:inline-block;margin-left:15px;width:0;content:attr(data-fill);white-space:nowrap}.uk-leader-fill.uk-leader-hide::after{display:none}:root{--uk-leader-fill-content:.}.uk-notification{position:fixed;top:10px;left:10px;z-index:1040;box-sizing:border-box;width:350px}.uk-notification-bottom-right,.uk-notification-top-right{left:auto;right:10px}.uk-notification-bottom-center,.uk-notification-top-center{left:50%;margin-left:-175px}.uk-notification-bottom-center,.uk-notification-bottom-left,.uk-notification-bottom-right{top:auto;bottom:10px}@media (max-width:639px){.uk-notification{left:10px;right:10px;width:auto;margin:0}}.uk-notification-message{position:relative;padding:15px;background:#f8f8f8;color:#666;font-size:1.25rem;line-height:1.4;cursor:pointer}*+.uk-notification-message{margin-top:10px}.uk-notification-close{display:none;position:absolute;top:20px;right:15px}.uk-notification-message:hover .uk-notification-close{display:block}.uk-notification-message-primary{color:#1e87f0}.uk-notification-message-success{color:#32d296}.uk-notification-message-warning{color:#faa05a}.uk-notification-message-danger{color:#f0506e}.uk-tooltip{display:none;position:absolute;z-index:1030;--uk-position-offset:10px;--uk-position-viewport-offset:10;top:0;box-sizing:border-box;max-width:200px;padding:3px 6px;background:#666;border-radius:2px;color:#fff;font-size:12px}.uk-tooltip.uk-active{display:block}.uk-sortable{position:relative}.uk-sortable>:last-child{margin-bottom:0}.uk-sortable-drag{position:fixed!important;z-index:1050!important;pointer-events:none}.uk-sortable-placeholder{opacity:0;pointer-events:none}.uk-sortable-empty{min-height:50px}.uk-sortable-handle:hover{cursor:move}.uk-countdown-number{font-variant-numeric:tabular-nums;font-size:2rem;line-height:.8}@media (min-width:640px){.uk-countdown-number{font-size:4rem}}@media (min-width:960px){.uk-countdown-number{font-size:6rem}}.uk-countdown-separator{font-size:1rem;line-height:1.6}@media (min-width:640px){.uk-countdown-separator{font-size:2rem}}@media (min-width:960px){.uk-countdown-separator{font-size:3rem}}.uk-thumbnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-left:-15px}.uk-thumbnav>*{padding-left:15px}.uk-thumbnav>*>*{display:inline-block;position:relative}.uk-thumbnav>*>::after{content:"";position:absolute;top:0;bottom:0;left:0;right:0;background-image:linear-gradient(180deg,rgba(255,255,255,0),rgba(255,255,255,.4));transition:opacity .1s ease-in-out}.uk-thumbnav>*>:hover::after{opacity:0}.uk-thumbnav>.uk-active>::after{opacity:0}.uk-thumbnav-vertical{flex-direction:column;margin-left:0;margin-top:-15px}.uk-thumbnav-vertical>*{padding-left:0;padding-top:15px}.uk-iconnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-left:-10px}.uk-iconnav>*{padding-left:10px}.uk-iconnav>*>a{display:flex;align-items:center;column-gap:.25em;line-height:0;color:#999;text-decoration:none;font-size:.875rem;transition:.1s ease-in-out;transition-property:color,background-color}.uk-iconnav>*>a:hover{color:#666}.uk-iconnav>.uk-active>a{color:#666}.uk-iconnav-vertical{flex-direction:column;margin-left:0;margin-top:-10px}.uk-iconnav-vertical>*{padding-left:0;padding-top:10px}.uk-grid{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none}.uk-grid>*{margin:0}.uk-grid>*>:last-child{margin-bottom:0}.uk-grid{margin-left:-30px}.uk-grid>*{padding-left:30px}*+.uk-grid-margin,.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin{margin-top:30px}@media (min-width:1200px){.uk-grid{margin-left:-40px}.uk-grid>*{padding-left:40px}*+.uk-grid-margin,.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin{margin-top:40px}}.uk-grid-column-small,.uk-grid-small{margin-left:-15px}.uk-grid-column-small>*,.uk-grid-small>*{padding-left:15px}*+.uk-grid-margin-small,.uk-grid+.uk-grid-row-small,.uk-grid+.uk-grid-small,.uk-grid-row-small>.uk-grid-margin,.uk-grid-small>.uk-grid-margin{margin-top:15px}.uk-grid-column-medium,.uk-grid-medium{margin-left:-30px}.uk-grid-column-medium>*,.uk-grid-medium>*{padding-left:30px}*+.uk-grid-margin-medium,.uk-grid+.uk-grid-medium,.uk-grid+.uk-grid-row-medium,.uk-grid-medium>.uk-grid-margin,.uk-grid-row-medium>.uk-grid-margin{margin-top:30px}.uk-grid-column-large,.uk-grid-large{margin-left:-40px}.uk-grid-column-large>*,.uk-grid-large>*{padding-left:40px}*+.uk-grid-margin-large,.uk-grid+.uk-grid-large,.uk-grid+.uk-grid-row-large,.uk-grid-large>.uk-grid-margin,.uk-grid-row-large>.uk-grid-margin{margin-top:40px}@media (min-width:1200px){.uk-grid-column-large,.uk-grid-large{margin-left:-70px}.uk-grid-column-large>*,.uk-grid-large>*{padding-left:70px}*+.uk-grid-margin-large,.uk-grid+.uk-grid-large,.uk-grid+.uk-grid-row-large,.uk-grid-large>.uk-grid-margin,.uk-grid-row-large>.uk-grid-margin{margin-top:70px}}.uk-grid-collapse,.uk-grid-column-collapse{margin-left:0}.uk-grid-collapse>*,.uk-grid-column-collapse>*{padding-left:0}.uk-grid+.uk-grid-collapse,.uk-grid+.uk-grid-row-collapse,.uk-grid-collapse>.uk-grid-margin,.uk-grid-row-collapse>.uk-grid-margin{margin-top:0}.uk-grid-divider>*{position:relative}.uk-grid-divider>:not(.uk-first-column)::before{content:"";position:absolute;top:0;bottom:0;border-left:1px solid #e5e5e5}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{content:"";position:absolute;left:0;right:0;border-top:1px solid #e5e5e5}.uk-grid-divider{margin-left:-60px}.uk-grid-divider>*{padding-left:60px}.uk-grid-divider>:not(.uk-first-column)::before{left:30px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-30px;left:60px}@media (min-width:1200px){.uk-grid-divider{margin-left:-80px}.uk-grid-divider>*{padding-left:80px}.uk-grid-divider>:not(.uk-first-column)::before{left:40px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-40px;left:80px}}.uk-grid-divider.uk-grid-column-small,.uk-grid-divider.uk-grid-small{margin-left:-30px}.uk-grid-divider.uk-grid-column-small>*,.uk-grid-divider.uk-grid-small>*{padding-left:30px}.uk-grid-divider.uk-grid-column-small>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-small>:not(.uk-first-column)::before{left:15px}.uk-grid-divider.uk-grid-row-small.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin{margin-top:30px}.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin::before{top:-15px;left:30px}.uk-grid-divider.uk-grid-row-small.uk-grid-stack>.uk-grid-margin::before{top:-15px}.uk-grid-divider.uk-grid-column-small.uk-grid-stack>.uk-grid-margin::before{left:30px}.uk-grid-divider.uk-grid-column-medium,.uk-grid-divider.uk-grid-medium{margin-left:-60px}.uk-grid-divider.uk-grid-column-medium>*,.uk-grid-divider.uk-grid-medium>*{padding-left:60px}.uk-grid-divider.uk-grid-column-medium>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-medium>:not(.uk-first-column)::before{left:30px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-medium.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px;left:60px}.uk-grid-divider.uk-grid-row-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px}.uk-grid-divider.uk-grid-column-medium.uk-grid-stack>.uk-grid-margin::before{left:60px}.uk-grid-divider.uk-grid-column-large,.uk-grid-divider.uk-grid-large{margin-left:-80px}.uk-grid-divider.uk-grid-column-large>*,.uk-grid-divider.uk-grid-large>*{padding-left:80px}.uk-grid-divider.uk-grid-column-large>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{left:40px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-40px;left:80px}.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin::before{top:-40px}.uk-grid-divider.uk-grid-column-large.uk-grid-stack>.uk-grid-margin::before{left:80px}@media (min-width:1200px){.uk-grid-divider.uk-grid-column-large,.uk-grid-divider.uk-grid-large{margin-left:-140px}.uk-grid-divider.uk-grid-column-large>*,.uk-grid-divider.uk-grid-large>*{padding-left:140px}.uk-grid-divider.uk-grid-column-large>:not(.uk-first-column)::before,.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{left:70px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin,.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin{margin-top:140px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-70px;left:140px}.uk-grid-divider.uk-grid-row-large.uk-grid-stack>.uk-grid-margin::before{top:-70px}.uk-grid-divider.uk-grid-column-large.uk-grid-stack>.uk-grid-margin::before{left:140px}}.uk-grid-item-match,.uk-grid-match>*{display:flex;flex-wrap:wrap}.uk-grid-item-match>:not([class*=uk-width]),.uk-grid-match>*>:not([class*=uk-width]){box-sizing:border-box;width:100%;flex:auto}.uk-nav,.uk-nav ul{margin:0;padding:0;list-style:none}.uk-nav li>a{display:flex;align-items:center;column-gap:.25em;text-decoration:none}.uk-nav>li>a{padding:5px 0}ul.uk-nav-sub{padding:5px 0 5px 15px}.uk-nav-sub ul{padding-left:15px}.uk-nav-sub a{padding:2px 0}.uk-nav-parent-icon{margin-left:auto;transition:transform .3s ease-out}.uk-nav>li.uk-open>a .uk-nav-parent-icon{transform:rotateX(180deg)}.uk-nav-header{padding:5px 0;text-transform:uppercase;font-size:.875rem}.uk-nav-header:not(:first-child){margin-top:20px}.uk-nav .uk-nav-divider{margin:5px 0}.uk-nav-default{font-size:.875rem;line-height:1.5}.uk-nav-default>li>a{color:#999}.uk-nav-default>li>a:hover{color:#666}.uk-nav-default>li.uk-active>a{color:#333}.uk-nav-default .uk-nav-subtitle{font-size:12px}.uk-nav-default .uk-nav-header{color:#333}.uk-nav-default .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-default .uk-nav-sub{font-size:.875rem;line-height:1.5}.uk-nav-default .uk-nav-sub a{color:#999}.uk-nav-default .uk-nav-sub a:hover{color:#666}.uk-nav-default .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-primary{font-size:1.5rem;line-height:1.5}.uk-nav-primary>li>a{color:#999}.uk-nav-primary>li>a:hover{color:#666}.uk-nav-primary>li.uk-active>a{color:#333}.uk-nav-primary .uk-nav-subtitle{font-size:1.25rem}.uk-nav-primary .uk-nav-header{color:#333}.uk-nav-primary .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-primary .uk-nav-sub{font-size:1.25rem;line-height:1.5}.uk-nav-primary .uk-nav-sub a{color:#999}.uk-nav-primary .uk-nav-sub a:hover{color:#666}.uk-nav-primary .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-secondary{font-size:16px;line-height:1.5}.uk-nav-secondary>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider){margin-top:0}.uk-nav-secondary>li>a{color:#333;padding:10px 10px}.uk-nav-secondary>li>a:hover{color:#333;background-color:#f8f8f8}.uk-nav-secondary>li.uk-active>a{color:#333;background-color:#f8f8f8}.uk-nav-secondary .uk-nav-subtitle{font-size:.875rem;color:#999}.uk-nav-secondary>li>a:hover .uk-nav-subtitle{color:#666}.uk-nav-secondary>li.uk-active>a .uk-nav-subtitle{color:#333}.uk-nav-secondary .uk-nav-header{color:#333}.uk-nav-secondary .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-nav-secondary .uk-nav-sub{font-size:.875rem;line-height:1.5}.uk-nav-secondary .uk-nav-sub a{color:#999}.uk-nav-secondary .uk-nav-sub a:hover{color:#666}.uk-nav-secondary .uk-nav-sub li.uk-active>a{color:#333}.uk-nav-medium{font-size:2.8875rem;line-height:1}.uk-nav-large{font-size:3.4rem;line-height:1}.uk-nav-xlarge{font-size:4rem;line-height:1}@media (min-width:960px){.uk-nav-medium{font-size:3.5rem}.uk-nav-large{font-size:4rem}.uk-nav-xlarge{font-size:6rem}}@media (min-width:1200px){.uk-nav-medium{font-size:4rem}.uk-nav-large{font-size:6rem}.uk-nav-xlarge{font-size:8rem}}.uk-nav-center{text-align:center}.uk-nav-center li>a{justify-content:center}.uk-nav-center .uk-nav-sub,.uk-nav-center .uk-nav-sub ul{padding-left:0}.uk-nav-center .uk-nav-parent-icon{margin-left:.25em}.uk-nav.uk-nav-divider>:not(.uk-nav-header,.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider){margin-top:5px;padding-top:5px;border-top:1px solid #e5e5e5}.uk-navbar{display:flex;position:relative}.uk-navbar-container:not(.uk-navbar-transparent){background:#f8f8f8}.uk-navbar-left,.uk-navbar-right,[class*=uk-navbar-center]{display:flex;gap:15px;align-items:center}.uk-navbar-right{margin-left:auto}.uk-navbar-center:only-child{margin-left:auto;margin-right:auto;position:relative}.uk-navbar-center:not(:only-child){position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:max-content;box-sizing:border-box;z-index:990}.uk-navbar-center-left,.uk-navbar-center-right{position:absolute;top:0}.uk-navbar-center-left{right:calc(100% + 15px)}.uk-navbar-center-right{left:calc(100% + 15px)}[class*=uk-navbar-center-]{width:max-content;box-sizing:border-box}.uk-navbar-nav{display:flex;gap:15px;margin:0;padding:0;list-style:none}.uk-navbar-center:only-child,.uk-navbar-left,.uk-navbar-right{flex-wrap:wrap}.uk-navbar-item,.uk-navbar-nav>li>a,.uk-navbar-toggle{display:flex;justify-content:center;align-items:center;column-gap:.25em;box-sizing:border-box;min-height:80px;font-size:.875rem;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";text-decoration:none}.uk-navbar-nav>li>a{padding:0 0;color:#999;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color}.uk-navbar-nav>li:hover>a,.uk-navbar-nav>li>a[aria-expanded=true]{color:#666}.uk-navbar-nav>li>a:active{color:#333}.uk-navbar-nav>li.uk-active>a{color:#333}.uk-navbar-parent-icon{margin-left:4px;transition:transform .3s ease-out}.uk-navbar-nav>li>a[aria-expanded=true] .uk-navbar-parent-icon{transform:rotateX(180deg)}.uk-navbar-item{padding:0 0;color:#666}.uk-navbar-item>:last-child{margin-bottom:0}.uk-navbar-toggle{padding:0 0;color:#999}.uk-navbar-toggle:hover,.uk-navbar-toggle[aria-expanded=true]{color:#666;text-decoration:none}.uk-navbar-subtitle{font-size:.875rem}.uk-navbar-justify .uk-navbar-item,.uk-navbar-justify .uk-navbar-left,.uk-navbar-justify .uk-navbar-nav,.uk-navbar-justify .uk-navbar-nav>li,.uk-navbar-justify .uk-navbar-right,.uk-navbar-justify .uk-navbar-toggle{flex-grow:1}.uk-navbar-dropdown{--uk-position-offset:15px;--uk-position-shift-offset:0;--uk-position-viewport-offset:15px;--uk-inverse:dark;width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,.15)}.uk-navbar-dropdown>:last-child{margin-bottom:0}.uk-navbar-dropdown :focus-visible{outline-color:#333!important}.uk-navbar-dropdown .uk-drop-grid{margin-left:-30px}.uk-navbar-dropdown .uk-drop-grid>*{padding-left:30px}.uk-navbar-dropdown .uk-drop-grid>.uk-grid-margin{margin-top:30px}.uk-navbar-dropdown-width-2:not(.uk-drop-stack){width:400px}.uk-navbar-dropdown-width-3:not(.uk-drop-stack){width:600px}.uk-navbar-dropdown-width-4:not(.uk-drop-stack){width:800px}.uk-navbar-dropdown-width-5:not(.uk-drop-stack){width:1000px}.uk-navbar-dropdown-large{--uk-position-shift-offset:0;padding:40px}.uk-navbar-dropdown-dropbar{width:auto;background:0 0;padding:25px 0 25px 0;--uk-position-offset:0;--uk-position-shift-offset:0;--uk-position-viewport-offset:15px;box-shadow:none}@media (min-width:640px){.uk-navbar-dropdown-dropbar{--uk-position-viewport-offset:30px}}@media (min-width:960px){.uk-navbar-dropdown-dropbar{--uk-position-viewport-offset:40px}}.uk-navbar-dropdown-dropbar-large{--uk-position-shift-offset:0;padding-top:40px;padding-bottom:40px}.uk-navbar-dropdown-nav{font-size:.875rem}.uk-navbar-dropdown-nav>li>a{color:#999}.uk-navbar-dropdown-nav>li>a:hover{color:#666}.uk-navbar-dropdown-nav>li.uk-active>a{color:#333}.uk-navbar-dropdown-nav .uk-nav-subtitle{font-size:12px}.uk-navbar-dropdown-nav .uk-nav-header{color:#333}.uk-navbar-dropdown-nav .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-navbar-dropdown-nav .uk-nav-sub a{color:#999}.uk-navbar-dropdown-nav .uk-nav-sub a:hover{color:#666}.uk-navbar-dropdown-nav .uk-nav-sub li.uk-active>a{color:#333}.uk-navbar-container{transition:.1s ease-in-out;transition-property:background-color}@media (min-width:960px){.uk-navbar-left,.uk-navbar-right,[class*=uk-navbar-center]{gap:30px}.uk-navbar-center-left{right:calc(100% + 30px)}.uk-navbar-center-right{left:calc(100% + 30px)}}@media (min-width:960px){.uk-navbar-nav{gap:30px}}.uk-subnav{display:flex;flex-wrap:wrap;align-items:center;margin-left:-20px;padding:0;list-style:none}.uk-subnav>*{flex:none;padding-left:20px;position:relative}.uk-subnav>*>:first-child{display:flex;align-items:center;column-gap:.25em;color:#999;font-size:.875rem;text-transform:uppercase;transition:.1s ease-in-out;transition-property:color,background-color}.uk-subnav>*>a:hover{color:#666;text-decoration:none}.uk-subnav>.uk-active>a{color:#333}.uk-subnav-divider{margin-left:-41px}.uk-subnav-divider>*{display:flex;align-items:center}.uk-subnav-divider>::before{content:"";height:1.5em;margin-left:0;margin-right:20px;border-left:1px solid transparent}.uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{border-left-color:#e5e5e5}.uk-subnav-pill{margin-left:-20px}.uk-subnav-pill>*{padding-left:20px}.uk-subnav-pill>*>:first-child{padding:5px 10px;background:0 0;color:#999}.uk-subnav-pill>*>a:hover{background-color:#f8f8f8;color:#666}.uk-subnav-pill>*>a:active{background-color:#f8f8f8;color:#666}.uk-subnav-pill>.uk-active>a{background-color:#1e87f0;color:#fff}.uk-subnav>.uk-disabled>a{color:#999}.uk-breadcrumb{padding:0;list-style:none;font-size:0}.uk-breadcrumb>*{display:contents}.uk-breadcrumb>*>*{font-size:.875rem;color:#999}.uk-breadcrumb>*>:hover{color:#666;text-decoration:none}.uk-breadcrumb>:last-child>a:not([href]),.uk-breadcrumb>:last-child>span{color:#666}.uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before{content:"/";display:inline-block;margin:0 20px;font-size:.875rem;color:#999}.uk-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.uk-pagination>*{flex:none;padding-left:0;position:relative}.uk-pagination>*>*{display:flex;align-items:center;column-gap:.25em;padding:5px 10px;color:#999;transition:color .1s ease-in-out}.uk-pagination>*>:hover{color:#666;text-decoration:none}.uk-pagination>.uk-active>*{color:#666}.uk-pagination>.uk-disabled>*{color:#999}.uk-tab{display:flex;flex-wrap:wrap;margin-left:-20px;padding:0;list-style:none;position:relative}.uk-tab::before{content:"";position:absolute;bottom:0;left:20px;right:0;border-bottom:1px solid #e5e5e5}.uk-tab>*{flex:none;padding-left:20px;position:relative}.uk-tab>*>a{display:flex;align-items:center;column-gap:.25em;justify-content:center;padding:5px 10px;color:#999;border-bottom:1px solid transparent;font-size:.875rem;text-transform:uppercase;transition:color .1s ease-in-out}.uk-tab>*>a:hover{color:#666;text-decoration:none}.uk-tab>.uk-active>a{color:#333;border-color:#1e87f0}.uk-tab>.uk-disabled>a{color:#999}.uk-tab-bottom::before{top:0;bottom:auto}.uk-tab-bottom>*>a{border-top:1px solid transparent;border-bottom:none}.uk-tab-left,.uk-tab-right{flex-direction:column;margin-left:0}.uk-tab-left>*,.uk-tab-right>*{padding-left:0}.uk-tab-left::before{top:0;bottom:0;left:auto;right:0;border-left:1px solid #e5e5e5;border-bottom:none}.uk-tab-right::before{top:0;bottom:0;left:0;right:auto;border-left:1px solid #e5e5e5;border-bottom:none}.uk-tab-left>*>a{justify-content:left;border-right:1px solid transparent;border-bottom:none}.uk-tab-right>*>a{justify-content:left;border-left:1px solid transparent;border-bottom:none}.uk-tab .uk-dropdown{margin-left:30px}.uk-slidenav{padding:5px 10px;color:rgba(102,102,102,.5);transition:color .1s ease-in-out}.uk-slidenav:hover{color:rgba(102,102,102,.9)}.uk-slidenav:active{color:rgba(102,102,102,.5)}.uk-slidenav-large{padding:10px 10px}.uk-slidenav-container{display:flex}.uk-dotnav{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;margin-left:-12px}.uk-dotnav>*{flex:none;padding-left:12px}.uk-dotnav>*>*{display:block;box-sizing:border-box;width:10px;height:10px;border-radius:50%;background:0 0;text-indent:100%;overflow:hidden;white-space:nowrap;border:1px solid rgba(102,102,102,.4);transition:.2s ease-in-out;transition-property:background-color,border-color}.uk-dotnav>*>:hover{background-color:rgba(102,102,102,.6);border-color:transparent}.uk-dotnav>*>:active{background-color:rgba(102,102,102,.2);border-color:transparent}.uk-dotnav>.uk-active>*{background-color:rgba(102,102,102,.6);border-color:transparent}.uk-dotnav-vertical{flex-direction:column;margin-left:0;margin-top:-12px}.uk-dotnav-vertical>*{padding-left:0;padding-top:12px}.uk-dropdown{--uk-position-offset:10px;--uk-position-viewport-offset:15px;--uk-inverse:dark;width:auto;min-width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,.15)}.uk-dropdown>:last-child{margin-bottom:0}.uk-dropdown :focus-visible{outline-color:#333!important}.uk-dropdown-large{padding:40px}.uk-dropdown-dropbar{--uk-position-offset:10px;width:auto;background:0 0;padding:5px 0 25px 0;--uk-position-viewport-offset:15px;box-shadow:none}@media (min-width:640px){.uk-dropdown-dropbar{--uk-position-viewport-offset:30px}}@media (min-width:960px){.uk-dropdown-dropbar{--uk-position-viewport-offset:40px}}.uk-dropdown-dropbar-large{padding-top:40px;padding-bottom:40px}.uk-dropdown-nav{font-size:.875rem}.uk-dropdown-nav>li>a{color:#999}.uk-dropdown-nav>li.uk-active>a,.uk-dropdown-nav>li>a:hover{color:#666}.uk-dropdown-nav .uk-nav-subtitle{font-size:12px}.uk-dropdown-nav .uk-nav-header{color:#333}.uk-dropdown-nav .uk-nav-divider{border-top:1px solid #e5e5e5}.uk-dropdown-nav .uk-nav-sub a{color:#999}.uk-dropdown-nav .uk-nav-sub a:hover,.uk-dropdown-nav .uk-nav-sub li.uk-active>a{color:#666}.uk-lightbox{--uk-inverse:light;display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1010;background:#000;opacity:0;transition:opacity .15s linear;touch-action:pinch-zoom}.uk-lightbox.uk-open{display:block;opacity:1}.uk-lightbox :focus-visible{outline-color:rgba(255,255,255,.7)}.uk-lightbox-page{overflow:hidden}.uk-lightbox-items{margin:0;padding:0;list-style:none}.uk-lightbox-items>*{position:absolute;top:0;right:0;bottom:0;left:0;display:none;justify-content:center;align-items:flex-start;will-change:transform,opacity;overflow:auto}.uk-lightbox-items>.uk-active{display:flex}.uk-lightbox-items-fit>*{align-items:center}.uk-lightbox-items-fit>*>*{max-width:100vw;max-height:100vh}.uk-lightbox-items-fit>*>:not(iframe){width:auto;height:auto}.uk-lightbox-items.uk-lightbox-items-fit .uk-lightbox-zoom:hover{cursor:zoom-in}.uk-lightbox-items:not(.uk-lightbox-items-fit) .uk-lightbox-zoom:hover{cursor:zoom-out}.uk-lightbox-thumbnav-vertical :where(img,video){max-width:100px}.uk-lightbox-thumbnav:not(.uk-lightbox-thumbnav-vertical) :where(img,video){max-height:100px}.uk-lightbox-dotnav:empty,.uk-lightbox-thumbnav:empty{display:none}.uk-lightbox-caption:empty{display:none}.uk-lightbox-caption{padding:10px 10px;background:rgba(0,0,0,.3);color:rgba(255,255,255,.7)}.uk-lightbox-caption>*{color:rgba(255,255,255,.7)}.uk-lightbox-counter:empty{display:none}.uk-lightbox-iframe{width:80%;height:80%}[class*=uk-animation-]{animation:.5s ease-out both}.uk-animation-fade{animation-name:uk-fade;animation-duration:.8s;animation-timing-function:linear}.uk-animation-scale-up{animation-name:uk-fade,uk-scale-up}.uk-animation-scale-down{animation-name:uk-fade,uk-scale-down}.uk-animation-slide-top{animation-name:uk-fade,uk-slide-top}.uk-animation-slide-bottom{animation-name:uk-fade,uk-slide-bottom}.uk-animation-slide-left{animation-name:uk-fade,uk-slide-left}.uk-animation-slide-right{animation-name:uk-fade,uk-slide-right}.uk-animation-slide-top-small{animation-name:uk-fade,uk-slide-top-small}.uk-animation-slide-bottom-small{animation-name:uk-fade,uk-slide-bottom-small}.uk-animation-slide-left-small{animation-name:uk-fade,uk-slide-left-small}.uk-animation-slide-right-small{animation-name:uk-fade,uk-slide-right-small}.uk-animation-slide-top-medium{animation-name:uk-fade,uk-slide-top-medium}.uk-animation-slide-bottom-medium{animation-name:uk-fade,uk-slide-bottom-medium}.uk-animation-slide-left-medium{animation-name:uk-fade,uk-slide-left-medium}.uk-animation-slide-right-medium{animation-name:uk-fade,uk-slide-right-medium}.uk-animation-kenburns{animation-name:uk-kenburns;animation-duration:15s}.uk-animation-shake{animation-name:uk-shake}.uk-animation-stroke{animation-name:uk-stroke;animation-duration:2s;stroke-dasharray:var(--uk-animation-stroke)}.uk-animation-reverse{animation-direction:reverse;animation-timing-function:ease-in}.uk-animation-fast{animation-duration:.1s}.uk-animation-toggle:not(:hover):not(:focus) [class*=uk-animation-]{animation-name:none}@keyframes uk-fade{0%{opacity:0}100%{opacity:1}}@keyframes uk-scale-up{0%{transform:scale(.9)}100%{transform:scale(1)}}@keyframes uk-scale-down{0%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes uk-slide-top{0%{transform:translateY(-100%)}100%{transform:translateY(0)}}@keyframes uk-slide-bottom{0%{transform:translateY(100%)}100%{transform:translateY(0)}}@keyframes uk-slide-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes uk-slide-right{0%{transform:translateX(100%)}100%{transform:translateX(0)}}@keyframes uk-slide-top-small{0%{transform:translateY(-10px)}100%{transform:translateY(0)}}@keyframes uk-slide-bottom-small{0%{transform:translateY(10px)}100%{transform:translateY(0)}}@keyframes uk-slide-left-small{0%{transform:translateX(-10px)}100%{transform:translateX(0)}}@keyframes uk-slide-right-small{0%{transform:translateX(10px)}100%{transform:translateX(0)}}@keyframes uk-slide-top-medium{0%{transform:translateY(-50px)}100%{transform:translateY(0)}}@keyframes uk-slide-bottom-medium{0%{transform:translateY(50px)}100%{transform:translateY(0)}}@keyframes uk-slide-left-medium{0%{transform:translateX(-50px)}100%{transform:translateX(0)}}@keyframes uk-slide-right-medium{0%{transform:translateX(50px)}100%{transform:translateX(0)}}@keyframes uk-kenburns{0%{transform:scale(1)}100%{transform:scale(1.2)}}@keyframes uk-shake{0%,100%{transform:translateX(0)}10%{transform:translateX(-9px)}20%{transform:translateX(8px)}30%{transform:translateX(-7px)}40%{transform:translateX(6px)}50%{transform:translateX(-5px)}60%{transform:translateX(4px)}70%{transform:translateX(-3px)}80%{transform:translateX(2px)}90%{transform:translateX(-1px)}}@keyframes uk-stroke{0%{stroke-dashoffset:var(--uk-animation-stroke)}100%{stroke-dashoffset:0}}[class*=uk-child-width]>*{box-sizing:border-box;width:100%}.uk-child-width-1-2>*{width:50%}.uk-child-width-1-3>*{width:calc(100% / 3)}.uk-child-width-1-4>*{width:25%}.uk-child-width-1-5>*{width:20%}.uk-child-width-1-6>*{width:calc(100% / 6)}.uk-child-width-auto>*{width:auto}.uk-child-width-expand>:not([class*=uk-width]){flex:1;min-width:1px}@media (min-width:640px){.uk-child-width-1-1\@s>*{width:100%}.uk-child-width-1-2\@s>*{width:50%}.uk-child-width-1-3\@s>*{width:calc(100% / 3)}.uk-child-width-1-4\@s>*{width:25%}.uk-child-width-1-5\@s>*{width:20%}.uk-child-width-1-6\@s>*{width:calc(100% / 6)}.uk-child-width-auto\@s>*{width:auto}.uk-child-width-expand\@s>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@s>:not([class*=uk-width]),.uk-child-width-1-2\@s>:not([class*=uk-width]),.uk-child-width-1-3\@s>:not([class*=uk-width]),.uk-child-width-1-4\@s>:not([class*=uk-width]),.uk-child-width-1-5\@s>:not([class*=uk-width]),.uk-child-width-1-6\@s>:not([class*=uk-width]),.uk-child-width-auto\@s>:not([class*=uk-width]){flex:initial}}@media (min-width:960px){.uk-child-width-1-1\@m>*{width:100%}.uk-child-width-1-2\@m>*{width:50%}.uk-child-width-1-3\@m>*{width:calc(100% / 3)}.uk-child-width-1-4\@m>*{width:25%}.uk-child-width-1-5\@m>*{width:20%}.uk-child-width-1-6\@m>*{width:calc(100% / 6)}.uk-child-width-auto\@m>*{width:auto}.uk-child-width-expand\@m>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@m>:not([class*=uk-width]),.uk-child-width-1-2\@m>:not([class*=uk-width]),.uk-child-width-1-3\@m>:not([class*=uk-width]),.uk-child-width-1-4\@m>:not([class*=uk-width]),.uk-child-width-1-5\@m>:not([class*=uk-width]),.uk-child-width-1-6\@m>:not([class*=uk-width]),.uk-child-width-auto\@m>:not([class*=uk-width]){flex:initial}}@media (min-width:1200px){.uk-child-width-1-1\@l>*{width:100%}.uk-child-width-1-2\@l>*{width:50%}.uk-child-width-1-3\@l>*{width:calc(100% / 3)}.uk-child-width-1-4\@l>*{width:25%}.uk-child-width-1-5\@l>*{width:20%}.uk-child-width-1-6\@l>*{width:calc(100% / 6)}.uk-child-width-auto\@l>*{width:auto}.uk-child-width-expand\@l>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@l>:not([class*=uk-width]),.uk-child-width-1-2\@l>:not([class*=uk-width]),.uk-child-width-1-3\@l>:not([class*=uk-width]),.uk-child-width-1-4\@l>:not([class*=uk-width]),.uk-child-width-1-5\@l>:not([class*=uk-width]),.uk-child-width-1-6\@l>:not([class*=uk-width]),.uk-child-width-auto\@l>:not([class*=uk-width]){flex:initial}}@media (min-width:1600px){.uk-child-width-1-1\@xl>*{width:100%}.uk-child-width-1-2\@xl>*{width:50%}.uk-child-width-1-3\@xl>*{width:calc(100% / 3)}.uk-child-width-1-4\@xl>*{width:25%}.uk-child-width-1-5\@xl>*{width:20%}.uk-child-width-1-6\@xl>*{width:calc(100% / 6)}.uk-child-width-auto\@xl>*{width:auto}.uk-child-width-expand\@xl>:not([class*=uk-width]){flex:1;min-width:1px}.uk-child-width-1-1\@xl>:not([class*=uk-width]),.uk-child-width-1-2\@xl>:not([class*=uk-width]),.uk-child-width-1-3\@xl>:not([class*=uk-width]),.uk-child-width-1-4\@xl>:not([class*=uk-width]),.uk-child-width-1-5\@xl>:not([class*=uk-width]),.uk-child-width-1-6\@xl>:not([class*=uk-width]),.uk-child-width-auto\@xl>:not([class*=uk-width]){flex:initial}}[class*=uk-width]{box-sizing:border-box;width:100%;max-width:100%}.uk-width-1-2{width:50%}.uk-width-1-3{width:calc(100% / 3)}.uk-width-2-3{width:calc(200% / 3)}.uk-width-1-4{width:25%}.uk-width-3-4{width:75%}.uk-width-1-5{width:20%}.uk-width-2-5{width:40%}.uk-width-3-5{width:60%}.uk-width-4-5{width:80%}.uk-width-1-6{width:calc(100% / 6)}.uk-width-5-6{width:calc(500% / 6)}.uk-width-small{width:150px}.uk-width-medium{width:300px}.uk-width-large{width:450px}.uk-width-xlarge{width:600px}.uk-width-2xlarge{width:750px}.uk-width-auto{width:auto}.uk-width-expand{flex:1;min-width:1px}@media (min-width:640px){.uk-width-1-1\@s{width:100%}.uk-width-1-2\@s{width:50%}.uk-width-1-3\@s{width:calc(100% / 3)}.uk-width-2-3\@s{width:calc(200% / 3)}.uk-width-1-4\@s{width:25%}.uk-width-3-4\@s{width:75%}.uk-width-1-5\@s{width:20%}.uk-width-2-5\@s{width:40%}.uk-width-3-5\@s{width:60%}.uk-width-4-5\@s{width:80%}.uk-width-1-6\@s{width:calc(100% / 6)}.uk-width-5-6\@s{width:calc(500% / 6)}.uk-width-small\@s{width:150px}.uk-width-medium\@s{width:300px}.uk-width-large\@s{width:450px}.uk-width-xlarge\@s{width:600px}.uk-width-2xlarge\@s{width:750px}.uk-width-auto\@s{width:auto}.uk-width-expand\@s{flex:1;min-width:1px}.uk-width-1-1\@s,.uk-width-1-2\@s,.uk-width-1-3\@s,.uk-width-1-4\@s,.uk-width-1-5\@s,.uk-width-1-6\@s,.uk-width-2-3\@s,.uk-width-2-5\@s,.uk-width-2xlarge\@s,.uk-width-3-4\@s,.uk-width-3-5\@s,.uk-width-4-5\@s,.uk-width-5-6\@s,.uk-width-auto\@s,.uk-width-large\@s,.uk-width-medium\@s,.uk-width-small\@s,.uk-width-xlarge\@s{flex:initial}}@media (min-width:960px){.uk-width-1-1\@m{width:100%}.uk-width-1-2\@m{width:50%}.uk-width-1-3\@m{width:calc(100% / 3)}.uk-width-2-3\@m{width:calc(200% / 3)}.uk-width-1-4\@m{width:25%}.uk-width-3-4\@m{width:75%}.uk-width-1-5\@m{width:20%}.uk-width-2-5\@m{width:40%}.uk-width-3-5\@m{width:60%}.uk-width-4-5\@m{width:80%}.uk-width-1-6\@m{width:calc(100% / 6)}.uk-width-5-6\@m{width:calc(500% / 6)}.uk-width-small\@m{width:150px}.uk-width-medium\@m{width:300px}.uk-width-large\@m{width:450px}.uk-width-xlarge\@m{width:600px}.uk-width-2xlarge\@m{width:750px}.uk-width-auto\@m{width:auto}.uk-width-expand\@m{flex:1;min-width:1px}.uk-width-1-1\@m,.uk-width-1-2\@m,.uk-width-1-3\@m,.uk-width-1-4\@m,.uk-width-1-5\@m,.uk-width-1-6\@m,.uk-width-2-3\@m,.uk-width-2-5\@m,.uk-width-2xlarge\@m,.uk-width-3-4\@m,.uk-width-3-5\@m,.uk-width-4-5\@m,.uk-width-5-6\@m,.uk-width-auto\@m,.uk-width-large\@m,.uk-width-medium\@m,.uk-width-small\@m,.uk-width-xlarge\@m{flex:initial}}@media (min-width:1200px){.uk-width-1-1\@l{width:100%}.uk-width-1-2\@l{width:50%}.uk-width-1-3\@l{width:calc(100% / 3)}.uk-width-2-3\@l{width:calc(200% / 3)}.uk-width-1-4\@l{width:25%}.uk-width-3-4\@l{width:75%}.uk-width-1-5\@l{width:20%}.uk-width-2-5\@l{width:40%}.uk-width-3-5\@l{width:60%}.uk-width-4-5\@l{width:80%}.uk-width-1-6\@l{width:calc(100% / 6)}.uk-width-5-6\@l{width:calc(500% / 6)}.uk-width-small\@l{width:150px}.uk-width-medium\@l{width:300px}.uk-width-large\@l{width:450px}.uk-width-xlarge\@l{width:600px}.uk-width-2xlarge\@l{width:750px}.uk-width-auto\@l{width:auto}.uk-width-expand\@l{flex:1;min-width:1px}.uk-width-1-1\@l,.uk-width-1-2\@l,.uk-width-1-3\@l,.uk-width-1-4\@l,.uk-width-1-5\@l,.uk-width-1-6\@l,.uk-width-2-3\@l,.uk-width-2-5\@l,.uk-width-2xlarge\@l,.uk-width-3-4\@l,.uk-width-3-5\@l,.uk-width-4-5\@l,.uk-width-5-6\@l,.uk-width-auto\@l,.uk-width-large\@l,.uk-width-medium\@l,.uk-width-small\@l,.uk-width-xlarge\@l{flex:initial}}@media (min-width:1600px){.uk-width-1-1\@xl{width:100%}.uk-width-1-2\@xl{width:50%}.uk-width-1-3\@xl{width:calc(100% / 3)}.uk-width-2-3\@xl{width:calc(200% / 3)}.uk-width-1-4\@xl{width:25%}.uk-width-3-4\@xl{width:75%}.uk-width-1-5\@xl{width:20%}.uk-width-2-5\@xl{width:40%}.uk-width-3-5\@xl{width:60%}.uk-width-4-5\@xl{width:80%}.uk-width-1-6\@xl{width:calc(100% / 6)}.uk-width-5-6\@xl{width:calc(500% / 6)}.uk-width-small\@xl{width:150px}.uk-width-medium\@xl{width:300px}.uk-width-large\@xl{width:450px}.uk-width-xlarge\@xl{width:600px}.uk-width-2xlarge\@xl{width:750px}.uk-width-auto\@xl{width:auto}.uk-width-expand\@xl{flex:1;min-width:1px}.uk-width-1-1\@xl,.uk-width-1-2\@xl,.uk-width-1-3\@xl,.uk-width-1-4\@xl,.uk-width-1-5\@xl,.uk-width-1-6\@xl,.uk-width-2-3\@xl,.uk-width-2-5\@xl,.uk-width-2xlarge\@xl,.uk-width-3-4\@xl,.uk-width-3-5\@xl,.uk-width-4-5\@xl,.uk-width-5-6\@xl,.uk-width-auto\@xl,.uk-width-large\@xl,.uk-width-medium\@xl,.uk-width-small\@xl,.uk-width-xlarge\@xl{flex:initial}}.uk-width-max-content{width:max-content}.uk-width-min-content{width:min-content}[class*=uk-height]{box-sizing:border-box}.uk-height-1-1{height:100%}.uk-height-viewport{min-height:100vh}.uk-height-viewport-2{min-height:200vh}.uk-height-viewport-3{min-height:300vh}.uk-height-viewport-4{min-height:400vh}.uk-height-small{height:150px}.uk-height-medium{height:300px}.uk-height-large{height:450px}.uk-height-max-small{max-height:150px}.uk-height-max-medium{max-height:300px}.uk-height-max-large{max-height:450px}.uk-text-lead{font-size:1.5rem;line-height:1.5;color:#333}.uk-text-meta{font-size:.875rem;line-height:1.4;color:#999}.uk-text-meta>a{color:#999}.uk-text-meta>a:hover{color:#666;text-decoration:none}.uk-text-small{font-size:.875rem;line-height:1.5}.uk-text-large{font-size:1.5rem;line-height:1.5}.uk-text-default{font-size:16px;line-height:1.5}.uk-text-light{font-weight:300}.uk-text-normal{font-weight:400}.uk-text-bold{font-weight:700}.uk-text-lighter{font-weight:lighter}.uk-text-bolder{font-weight:bolder}.uk-text-italic{font-style:italic}.uk-text-capitalize{text-transform:capitalize!important}.uk-text-uppercase{text-transform:uppercase!important}.uk-text-lowercase{text-transform:lowercase!important}.uk-text-decoration-none{text-decoration:none!important}.uk-text-muted{color:#999!important}.uk-text-emphasis{color:#333!important}.uk-text-primary{color:#1e87f0!important}.uk-text-secondary{color:#222!important}.uk-text-success{color:#32d296!important}.uk-text-warning{color:#faa05a!important}.uk-text-danger{color:#f0506e!important}.uk-text-background{-webkit-background-clip:text;color:transparent!important;display:inline-block;background-color:#1e87f0;background-image:linear-gradient(90deg,#1e87f0 0,#411ef0 100%)}.uk-text-left{text-align:left!important}.uk-text-right{text-align:right!important}.uk-text-center{text-align:center!important}.uk-text-justify{text-align:justify!important}@media (min-width:640px){.uk-text-left\@s{text-align:left!important}.uk-text-right\@s{text-align:right!important}.uk-text-center\@s{text-align:center!important}}@media (min-width:960px){.uk-text-left\@m{text-align:left!important}.uk-text-right\@m{text-align:right!important}.uk-text-center\@m{text-align:center!important}}@media (min-width:1200px){.uk-text-left\@l{text-align:left!important}.uk-text-right\@l{text-align:right!important}.uk-text-center\@l{text-align:center!important}}@media (min-width:1600px){.uk-text-left\@xl{text-align:left!important}.uk-text-right\@xl{text-align:right!important}.uk-text-center\@xl{text-align:center!important}}.uk-text-top{vertical-align:top!important}.uk-text-middle{vertical-align:middle!important}.uk-text-bottom{vertical-align:bottom!important}.uk-text-baseline{vertical-align:baseline!important}.uk-text-nowrap{white-space:nowrap}.uk-text-truncate{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}td.uk-text-truncate,th.uk-text-truncate{max-width:0}.uk-text-break{overflow-wrap:break-word}td.uk-text-break,th.uk-text-break{word-break:break-word}.uk-text-stroke{-webkit-text-stroke:calc(1.4px + 0.002em);-webkit-text-fill-color:transparent}[class*=uk-column-]{column-gap:30px}@media (min-width:1200px){[class*=uk-column-]{column-gap:40px}}[class*=uk-column-] img{transform:translate3d(0,0,0)}.uk-column-divider{column-rule:1px solid #e5e5e5;column-gap:60px}@media (min-width:1200px){.uk-column-divider{column-gap:80px}}.uk-column-1-2{column-count:2}.uk-column-1-3{column-count:3}.uk-column-1-4{column-count:4}.uk-column-1-5{column-count:5}.uk-column-1-6{column-count:6}@media (min-width:640px){.uk-column-1-2\@s{column-count:2}.uk-column-1-3\@s{column-count:3}.uk-column-1-4\@s{column-count:4}.uk-column-1-5\@s{column-count:5}.uk-column-1-6\@s{column-count:6}}@media (min-width:960px){.uk-column-1-2\@m{column-count:2}.uk-column-1-3\@m{column-count:3}.uk-column-1-4\@m{column-count:4}.uk-column-1-5\@m{column-count:5}.uk-column-1-6\@m{column-count:6}}@media (min-width:1200px){.uk-column-1-2\@l{column-count:2}.uk-column-1-3\@l{column-count:3}.uk-column-1-4\@l{column-count:4}.uk-column-1-5\@l{column-count:5}.uk-column-1-6\@l{column-count:6}}@media (min-width:1600px){.uk-column-1-2\@xl{column-count:2}.uk-column-1-3\@xl{column-count:3}.uk-column-1-4\@xl{column-count:4}.uk-column-1-5\@xl{column-count:5}.uk-column-1-6\@xl{column-count:6}}.uk-column-span{column-span:all}[data-uk-cover]:where(canvas,iframe,svg),[uk-cover]:where(canvas,iframe,svg){max-width:none;position:absolute;left:50%;top:50%;--uk-position-translate-x:-50%;--uk-position-translate-y:-50%;transform:translate(var(--uk-position-translate-x),var(--uk-position-translate-y))}iframe[data-uk-cover],iframe[uk-cover]{pointer-events:none}[data-uk-cover]:where(img,video),[uk-cover]:where(img,video){position:absolute;top:0;left:0;width:100%;height:100%;box-sizing:border-box;object-fit:cover;object-position:center}.uk-cover-container{overflow:hidden;position:relative}.uk-background-default{background-color:#fff}.uk-background-muted{background-color:#f8f8f8}.uk-background-primary{background-color:#1e87f0}.uk-background-secondary{background-color:#222}.uk-background-contain,.uk-background-cover,.uk-background-height-1-1,.uk-background-width-1-1{background-position:50% 50%;background-repeat:no-repeat}.uk-background-cover{background-size:cover}.uk-background-contain{background-size:contain}.uk-background-width-1-1{background-size:100%}.uk-background-height-1-1{background-size:auto 100%}.uk-background-top-left{background-position:0 0}.uk-background-top-center{background-position:50% 0}.uk-background-top-right{background-position:100% 0}.uk-background-center-left{background-position:0 50%}.uk-background-center-center{background-position:50% 50%}.uk-background-center-right{background-position:100% 50%}.uk-background-bottom-left{background-position:0 100%}.uk-background-bottom-center{background-position:50% 100%}.uk-background-bottom-right{background-position:100% 100%}.uk-background-norepeat{background-repeat:no-repeat}.uk-background-fixed{background-attachment:fixed}@media (pointer:coarse){.uk-background-fixed{background-attachment:scroll}}@media (max-width:639px){.uk-background-image\@s{background-image:none!important}}@media (max-width:959px){.uk-background-image\@m{background-image:none!important}}@media (max-width:1199px){.uk-background-image\@l{background-image:none!important}}@media (max-width:1599px){.uk-background-image\@xl{background-image:none!important}}.uk-background-blend-multiply{background-blend-mode:multiply}.uk-background-blend-screen{background-blend-mode:screen}.uk-background-blend-overlay{background-blend-mode:overlay}.uk-background-blend-darken{background-blend-mode:darken}.uk-background-blend-lighten{background-blend-mode:lighten}.uk-background-blend-color-dodge{background-blend-mode:color-dodge}.uk-background-blend-color-burn{background-blend-mode:color-burn}.uk-background-blend-hard-light{background-blend-mode:hard-light}.uk-background-blend-soft-light{background-blend-mode:soft-light}.uk-background-blend-difference{background-blend-mode:difference}.uk-background-blend-exclusion{background-blend-mode:exclusion}.uk-background-blend-hue{background-blend-mode:hue}.uk-background-blend-saturation{background-blend-mode:saturation}.uk-background-blend-color{background-blend-mode:color}.uk-background-blend-luminosity{background-blend-mode:luminosity}[class*=uk-align]{display:block;margin-bottom:30px}*+[class*=uk-align]{margin-top:30px}.uk-align-center{margin-left:auto;margin-right:auto}.uk-align-left{margin-top:0;margin-right:30px;float:left}.uk-align-right{margin-top:0;margin-left:30px;float:right}@media (min-width:640px){.uk-align-left\@s{margin-top:0;margin-right:30px;float:left}.uk-align-right\@s{margin-top:0;margin-left:30px;float:right}}@media (min-width:960px){.uk-align-left\@m{margin-top:0;margin-right:30px;float:left}.uk-align-right\@m{margin-top:0;margin-left:30px;float:right}}@media (min-width:1200px){.uk-align-left\@l{margin-top:0;float:left}.uk-align-right\@l{margin-top:0;float:right}.uk-align-left,.uk-align-left\@l,.uk-align-left\@m,.uk-align-left\@s{margin-right:40px}.uk-align-right,.uk-align-right\@l,.uk-align-right\@m,.uk-align-right\@s{margin-left:40px}}@media (min-width:1600px){.uk-align-left\@xl{margin-top:0;margin-right:40px;float:left}.uk-align-right\@xl{margin-top:0;margin-left:40px;float:right}}.uk-svg,.uk-svg:not(.uk-preserve) [fill*="#"]:not(.uk-preserve){fill:currentcolor}.uk-svg:not(.uk-preserve) [stroke*="#"]:not(.uk-preserve){stroke:currentcolor}.uk-svg{transform:translate(0,0)}.uk-panel{display:flow-root;position:relative;box-sizing:border-box}.uk-panel>:last-child{margin-bottom:0}.uk-panel-scrollable{height:170px;padding:10px;border:1px solid #e5e5e5;overflow:auto;resize:both}.uk-clearfix::before{content:"";display:table-cell}.uk-clearfix::after{content:"";display:table;clear:both}.uk-float-left{float:left}.uk-float-right{float:right}[class*=uk-float-]{max-width:100%}.uk-overflow-hidden{overflow:hidden}.uk-overflow-auto{overflow:auto}.uk-overflow-auto>:last-child{margin-bottom:0}.uk-box-sizing-content{box-sizing:content-box}.uk-box-sizing-border{box-sizing:border-box}.uk-resize{resize:both}.uk-resize-horizontal{resize:horizontal}.uk-resize-vertical{resize:vertical}.uk-display-block{display:block!important}.uk-display-inline{display:inline!important}.uk-display-inline-block{display:inline-block!important}[class*=uk-inline]{display:inline-block;position:relative;max-width:100%;vertical-align:middle;-webkit-backface-visibility:hidden}.uk-inline-clip{overflow:hidden}.uk-preserve-width,.uk-preserve-width canvas,.uk-preserve-width img,.uk-preserve-width svg,.uk-preserve-width video{max-width:none}.uk-responsive-height,.uk-responsive-width{box-sizing:border-box}.uk-responsive-width{max-width:100%!important;height:auto}.uk-responsive-height{max-height:100%;width:auto;max-width:none}[data-uk-responsive],[uk-responsive]{max-width:100%}.uk-object-cover{object-fit:cover}.uk-object-contain{object-fit:contain}.uk-object-fill{object-fit:fill}.uk-object-none{object-fit:none}.uk-object-scale-down{object-fit:scale-down}.uk-object-top-left{object-position:0 0}.uk-object-top-center{object-position:50% 0}.uk-object-top-right{object-position:100% 0}.uk-object-center-left{object-position:0 50%}.uk-object-center-center{object-position:50% 50%}.uk-object-center-right{object-position:100% 50%}.uk-object-bottom-left{object-position:0 100%}.uk-object-bottom-center{object-position:50% 100%}.uk-object-bottom-right{object-position:100% 100%}.uk-border-circle{border-radius:50%}.uk-border-pill{border-radius:500px}.uk-border-rounded{border-radius:5px}.uk-inline-clip[class*=uk-border-]{-webkit-transform:translateZ(0)}.uk-box-shadow-small{box-shadow:0 2px 8px rgba(0,0,0,.08)}.uk-box-shadow-medium{box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-box-shadow-large{box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-box-shadow-xlarge{box-shadow:0 28px 50px rgba(0,0,0,.16)}[class*=uk-box-shadow-hover]{transition:box-shadow .1s ease-in-out}.uk-box-shadow-hover-small:hover{box-shadow:0 2px 8px rgba(0,0,0,.08)}.uk-box-shadow-hover-medium:hover{box-shadow:0 5px 15px rgba(0,0,0,.08)}.uk-box-shadow-hover-large:hover{box-shadow:0 14px 25px rgba(0,0,0,.16)}.uk-box-shadow-hover-xlarge:hover{box-shadow:0 28px 50px rgba(0,0,0,.16)}@supports (filter:blur(0)){.uk-box-shadow-bottom{display:inline-block;position:relative;z-index:0;max-width:100%;vertical-align:middle}.uk-box-shadow-bottom::after{content:"";position:absolute;bottom:-30px;left:0;right:0;z-index:-1;height:30px;border-radius:100%;background:#444;filter:blur(20px);will-change:filter}}.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{display:block;margin-right:10px;float:left;font-size:4.5em;line-height:1;margin-bottom:-2px}@-moz-document url-prefix(){.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{margin-top:1.1%}}.uk-logo{font-size:1.5rem;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";color:#333;text-decoration:none}:where(.uk-logo){display:inline-block;vertical-align:middle}.uk-logo:hover{color:#333;text-decoration:none}.uk-logo :where(img,svg,video){display:block}.uk-logo-inverse{display:none}.uk-disabled{pointer-events:none}.uk-drag,.uk-drag *{cursor:move}.uk-drag iframe{pointer-events:none}.uk-dragover{box-shadow:0 0 20px rgba(100,100,100,.3)}.uk-blend-multiply{mix-blend-mode:multiply}.uk-blend-screen{mix-blend-mode:screen}.uk-blend-overlay{mix-blend-mode:overlay}.uk-blend-darken{mix-blend-mode:darken}.uk-blend-lighten{mix-blend-mode:lighten}.uk-blend-color-dodge{mix-blend-mode:color-dodge}.uk-blend-color-burn{mix-blend-mode:color-burn}.uk-blend-hard-light{mix-blend-mode:hard-light}.uk-blend-soft-light{mix-blend-mode:soft-light}.uk-blend-difference{mix-blend-mode:difference}.uk-blend-exclusion{mix-blend-mode:exclusion}.uk-blend-hue{mix-blend-mode:hue}.uk-blend-saturation{mix-blend-mode:saturation}.uk-blend-color{mix-blend-mode:color}.uk-blend-luminosity{mix-blend-mode:luminosity}.uk-transform-center{transform:translate(-50%,-50%)}.uk-transform-origin-top-left{transform-origin:0 0}.uk-transform-origin-top-center{transform-origin:50% 0}.uk-transform-origin-top-right{transform-origin:100% 0}.uk-transform-origin-center-left{transform-origin:0 50%}.uk-transform-origin-center-right{transform-origin:100% 50%}.uk-transform-origin-bottom-left{transform-origin:0 100%}.uk-transform-origin-bottom-center{transform-origin:50% 100%}.uk-transform-origin-bottom-right{transform-origin:100% 100%}.uk-flex{display:flex}.uk-flex-inline{display:inline-flex}.uk-flex-left{justify-content:flex-start}.uk-flex-center{justify-content:center}.uk-flex-right{justify-content:flex-end}.uk-flex-between{justify-content:space-between}.uk-flex-around{justify-content:space-around}@media (min-width:640px){.uk-flex-left\@s{justify-content:flex-start}.uk-flex-center\@s{justify-content:center}.uk-flex-right\@s{justify-content:flex-end}.uk-flex-between\@s{justify-content:space-between}.uk-flex-around\@s{justify-content:space-around}}@media (min-width:960px){.uk-flex-left\@m{justify-content:flex-start}.uk-flex-center\@m{justify-content:center}.uk-flex-right\@m{justify-content:flex-end}.uk-flex-between\@m{justify-content:space-between}.uk-flex-around\@m{justify-content:space-around}}@media (min-width:1200px){.uk-flex-left\@l{justify-content:flex-start}.uk-flex-center\@l{justify-content:center}.uk-flex-right\@l{justify-content:flex-end}.uk-flex-between\@l{justify-content:space-between}.uk-flex-around\@l{justify-content:space-around}}@media (min-width:1600px){.uk-flex-left\@xl{justify-content:flex-start}.uk-flex-center\@xl{justify-content:center}.uk-flex-right\@xl{justify-content:flex-end}.uk-flex-between\@xl{justify-content:space-between}.uk-flex-around\@xl{justify-content:space-around}}.uk-flex-stretch{align-items:stretch}.uk-flex-top{align-items:flex-start}.uk-flex-middle{align-items:center}.uk-flex-bottom{align-items:flex-end}@media (min-width:640px){.uk-flex-stretch\@s{align-items:stretch}.uk-flex-top\@s{align-items:flex-start}.uk-flex-middle\@s{align-items:center}.uk-flex-bottom\@s{align-items:flex-end}}@media (min-width:960px){.uk-flex-stretch\@m{align-items:stretch}.uk-flex-top\@m{align-items:flex-start}.uk-flex-middle\@m{align-items:center}.uk-flex-bottom\@m{align-items:flex-end}}@media (min-width:1200px){.uk-flex-stretch\@l{align-items:stretch}.uk-flex-top\@l{align-items:flex-start}.uk-flex-middle\@l{align-items:center}.uk-flex-bottom\@l{align-items:flex-end}}@media (min-width:1600px){.uk-flex-stretch\@xl{align-items:stretch}.uk-flex-top\@xl{align-items:flex-start}.uk-flex-middle\@xl{align-items:center}.uk-flex-bottom\@xl{align-items:flex-end}}.uk-flex-row{flex-direction:row}.uk-flex-row-reverse{flex-direction:row-reverse}.uk-flex-column{flex-direction:column}.uk-flex-column-reverse{flex-direction:column-reverse}@media (min-width:640px){.uk-flex-row\@s{flex-direction:row}.uk-flex-column\@s{flex-direction:column}}@media (min-width:960px){.uk-flex-row\@m{flex-direction:row}.uk-flex-column\@m{flex-direction:column}}@media (min-width:1200px){.uk-flex-row\@l{flex-direction:row}.uk-flex-column\@l{flex-direction:column}}@media (min-width:1600px){.uk-flex-row\@xl{flex-direction:row}.uk-flex-column\@xl{flex-direction:column}}.uk-flex-nowrap{flex-wrap:nowrap}.uk-flex-wrap{flex-wrap:wrap}.uk-flex-wrap-reverse{flex-wrap:wrap-reverse}.uk-flex-wrap-stretch{align-content:stretch}.uk-flex-wrap-top{align-content:flex-start}.uk-flex-wrap-middle{align-content:center}.uk-flex-wrap-bottom{align-content:flex-end}.uk-flex-wrap-between{align-content:space-between}.uk-flex-wrap-around{align-content:space-around}.uk-flex-first{order:-1}.uk-flex-last{order:99}@media (min-width:640px){.uk-flex-first\@s{order:-1}.uk-flex-last\@s{order:99}}@media (min-width:960px){.uk-flex-first\@m{order:-1}.uk-flex-last\@m{order:99}}@media (min-width:1200px){.uk-flex-first\@l{order:-1}.uk-flex-last\@l{order:99}}@media (min-width:1600px){.uk-flex-first\@xl{order:-1}.uk-flex-last\@xl{order:99}}.uk-flex-initial{flex:initial}.uk-flex-none{flex:none}.uk-flex-auto{flex:auto}.uk-flex-1{flex:1}@media (min-width:640px){.uk-flex-initial\@s{flex:initial}.uk-flex-none\@s{flex:none}.uk-flex-1\@s{flex:1}}@media (min-width:960px){.uk-flex-initial\@m{flex:initial}.uk-flex-none\@m{flex:none}.uk-flex-1\@m{flex:1}}@media (min-width:1200px){.uk-flex-initial\@l{flex:initial}.uk-flex-none\@l{flex:none}.uk-flex-1\@l{flex:1}}@media (min-width:1600px){.uk-flex-initial\@xl{flex:initial}.uk-flex-none\@xl{flex:none}.uk-flex-1\@xl{flex:1}}.uk-margin{margin-bottom:20px}*+.uk-margin{margin-top:20px!important}.uk-margin-top{margin-top:20px!important}.uk-margin-bottom{margin-bottom:20px!important}.uk-margin-left{margin-left:20px!important}.uk-margin-right{margin-right:20px!important}.uk-margin-xsmall{margin-bottom:5px}*+.uk-margin-xsmall{margin-top:5px!important}.uk-margin-xsmall-top{margin-top:5px!important}.uk-margin-xsmall-bottom{margin-bottom:5px!important}.uk-margin-xsmall-left{margin-left:5px!important}.uk-margin-xsmall-right{margin-right:5px!important}.uk-margin-small{margin-bottom:10px}*+.uk-margin-small{margin-top:10px!important}.uk-margin-small-top{margin-top:10px!important}.uk-margin-small-bottom{margin-bottom:10px!important}.uk-margin-small-left{margin-left:10px!important}.uk-margin-small-right{margin-right:10px!important}.uk-margin-medium{margin-bottom:40px}*+.uk-margin-medium{margin-top:40px!important}.uk-margin-medium-top{margin-top:40px!important}.uk-margin-medium-bottom{margin-bottom:40px!important}.uk-margin-medium-left{margin-left:40px!important}.uk-margin-medium-right{margin-right:40px!important}.uk-margin-large{margin-bottom:40px}*+.uk-margin-large{margin-top:40px!important}.uk-margin-large-top{margin-top:40px!important}.uk-margin-large-bottom{margin-bottom:40px!important}.uk-margin-large-left{margin-left:40px!important}.uk-margin-large-right{margin-right:40px!important}@media (min-width:1200px){.uk-margin-large{margin-bottom:70px}*+.uk-margin-large{margin-top:70px!important}.uk-margin-large-top{margin-top:70px!important}.uk-margin-large-bottom{margin-bottom:70px!important}.uk-margin-large-left{margin-left:70px!important}.uk-margin-large-right{margin-right:70px!important}}.uk-margin-xlarge{margin-bottom:70px}*+.uk-margin-xlarge{margin-top:70px!important}.uk-margin-xlarge-top{margin-top:70px!important}.uk-margin-xlarge-bottom{margin-bottom:70px!important}.uk-margin-xlarge-left{margin-left:70px!important}.uk-margin-xlarge-right{margin-right:70px!important}@media (min-width:1200px){.uk-margin-xlarge{margin-bottom:140px}*+.uk-margin-xlarge{margin-top:140px!important}.uk-margin-xlarge-top{margin-top:140px!important}.uk-margin-xlarge-bottom{margin-bottom:140px!important}.uk-margin-xlarge-left{margin-left:140px!important}.uk-margin-xlarge-right{margin-right:140px!important}}.uk-margin-auto{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-top{margin-top:auto!important}.uk-margin-auto-bottom{margin-bottom:auto!important}.uk-margin-auto-left{margin-left:auto!important}.uk-margin-auto-right{margin-right:auto!important}.uk-margin-auto-vertical{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:640px){.uk-margin-auto\@s{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@s{margin-left:auto!important}.uk-margin-auto-right\@s{margin-right:auto!important}}@media (min-width:960px){.uk-margin-auto\@m{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@m{margin-left:auto!important}.uk-margin-auto-right\@m{margin-right:auto!important}}@media (min-width:1200px){.uk-margin-auto\@l{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@l{margin-left:auto!important}.uk-margin-auto-right\@l{margin-right:auto!important}}@media (min-width:1600px){.uk-margin-auto\@xl{margin-left:auto!important;margin-right:auto!important}.uk-margin-auto-left\@xl{margin-left:auto!important}.uk-margin-auto-right\@xl{margin-right:auto!important}}.uk-margin-remove{margin:0!important}.uk-margin-remove-top{margin-top:0!important}.uk-margin-remove-bottom{margin-bottom:0!important}.uk-margin-remove-left{margin-left:0!important}.uk-margin-remove-right{margin-right:0!important}.uk-margin-remove-vertical{margin-top:0!important;margin-bottom:0!important}.uk-margin-remove-adjacent+*,.uk-margin-remove-first-child>:first-child{margin-top:0!important}.uk-margin-remove-last-child>:last-child{margin-bottom:0!important}@media (min-width:640px){.uk-margin-remove-left\@s{margin-left:0!important}.uk-margin-remove-right\@s{margin-right:0!important}}@media (min-width:960px){.uk-margin-remove-left\@m{margin-left:0!important}.uk-margin-remove-right\@m{margin-right:0!important}}@media (min-width:1200px){.uk-margin-remove-left\@l{margin-left:0!important}.uk-margin-remove-right\@l{margin-right:0!important}}@media (min-width:1600px){.uk-margin-remove-left\@xl{margin-left:0!important}.uk-margin-remove-right\@xl{margin-right:0!important}}.uk-padding{padding:30px}@media (min-width:1200px){.uk-padding{padding:40px}}.uk-padding-small{padding:15px}.uk-padding-large{padding:40px}@media (min-width:1200px){.uk-padding-large{padding:70px}}.uk-padding-remove{padding:0!important}.uk-padding-remove-top{padding-top:0!important}.uk-padding-remove-bottom{padding-bottom:0!important}.uk-padding-remove-left{padding-left:0!important}.uk-padding-remove-right{padding-right:0!important}.uk-padding-remove-vertical{padding-top:0!important;padding-bottom:0!important}.uk-padding-remove-horizontal{padding-left:0!important;padding-right:0!important}:root{--uk-position-margin-offset:0px}[class*=uk-position-bottom],[class*=uk-position-center],[class*=uk-position-left],[class*=uk-position-right],[class*=uk-position-top]{position:absolute!important;max-width:calc(100% - (var(--uk-position-margin-offset) * 2));box-sizing:border-box}.uk-position-top{top:0;left:0;right:0}.uk-position-bottom{bottom:0;left:0;right:0}.uk-position-left{top:0;bottom:0;left:0}.uk-position-right{top:0;bottom:0;right:0}.uk-position-top-left{top:0;left:0}.uk-position-top-right{top:0;right:0}.uk-position-bottom-left{bottom:0;left:0}.uk-position-bottom-right{bottom:0;right:0}.uk-position-center{top:calc(50% - var(--uk-position-margin-offset));left:calc(50% - var(--uk-position-margin-offset));--uk-position-translate-x:-50%;--uk-position-translate-y:-50%;transform:translate(var(--uk-position-translate-x),var(--uk-position-translate-y));width:max-content}.uk-position-center-vertical,[class*=uk-position-center-left],[class*=uk-position-center-right]{top:calc(50% - var(--uk-position-margin-offset));--uk-position-translate-y:-50%;transform:translate(0,var(--uk-position-translate-y))}.uk-position-center-left{left:0}.uk-position-center-right{right:0}.uk-position-center-vertical{left:0;right:0}.uk-position-center-left-out{right:100%;width:max-content}.uk-position-center-right-out{left:100%;width:max-content}.uk-position-bottom-center,.uk-position-center-horizontal,.uk-position-top-center{left:calc(50% - var(--uk-position-margin-offset));--uk-position-translate-x:-50%;transform:translate(var(--uk-position-translate-x),0);width:max-content}.uk-position-top-center{top:0}.uk-position-bottom-center{bottom:0}.uk-position-center-horizontal{top:0;bottom:0}.uk-position-cover{position:absolute;top:0;bottom:0;left:0;right:0}.uk-position-small{margin:15px;--uk-position-margin-offset:15px}.uk-position-medium{margin:30px;--uk-position-margin-offset:30px}.uk-position-large{margin:30px;--uk-position-margin-offset:30px}@media (min-width:1200px){.uk-position-large{margin:50px;--uk-position-margin-offset:50px}}.uk-position-relative{position:relative!important}.uk-position-absolute{position:absolute!important}.uk-position-fixed{position:fixed!important}.uk-position-sticky{position:sticky!important}.uk-position-z-index{z-index:1}.uk-position-z-index-zero{z-index:0}.uk-position-z-index-negative{z-index:-1}.uk-position-z-index-high{z-index:990}:where(.uk-transition-fade),:where([class*=uk-transition-scale]),:where([class*=uk-transition-slide]){--uk-position-translate-x:0;--uk-position-translate-y:0}.uk-transition-fade,[class*=uk-transition-scale],[class*=uk-transition-slide]{--uk-translate-x:0;--uk-translate-y:0;--uk-scale-x:1;--uk-scale-y:1;transform:translate(var(--uk-position-translate-x),var(--uk-position-translate-y)) translate(var(--uk-translate-x),var(--uk-translate-y)) scale(var(--uk-scale-x),var(--uk-scale-y));transition:.3s ease-out;transition-property:opacity,transform,filter;opacity:0}.uk-transition-active.uk-active .uk-transition-fade,.uk-transition-toggle:focus .uk-transition-fade,.uk-transition-toggle:focus-within .uk-transition-fade,.uk-transition-toggle:hover .uk-transition-fade{opacity:1}[class*=uk-transition-scale]{-webkit-backface-visibility:hidden}.uk-transition-scale-up{--uk-scale-x:1;--uk-scale-y:1}.uk-transition-scale-down{--uk-scale-x:1.03;--uk-scale-y:1.03}.uk-transition-active.uk-active .uk-transition-scale-up,.uk-transition-toggle:focus .uk-transition-scale-up,.uk-transition-toggle:focus-within .uk-transition-scale-up,.uk-transition-toggle:hover .uk-transition-scale-up{--uk-scale-x:1.03;--uk-scale-y:1.03;opacity:1}.uk-transition-active.uk-active .uk-transition-scale-down,.uk-transition-toggle:focus .uk-transition-scale-down,.uk-transition-toggle:focus-within .uk-transition-scale-down,.uk-transition-toggle:hover .uk-transition-scale-down{--uk-scale-x:1;--uk-scale-y:1;opacity:1}.uk-transition-slide-top{--uk-translate-y:-100%}.uk-transition-slide-bottom{--uk-translate-y:100%}.uk-transition-slide-left{--uk-translate-x:-100%}.uk-transition-slide-right{--uk-translate-x:100%}.uk-transition-slide-top-small{--uk-translate-y:calc(-1 * 10px)}.uk-transition-slide-bottom-small{--uk-translate-y:10px}.uk-transition-slide-left-small{--uk-translate-x:calc(-1 * 10px)}.uk-transition-slide-right-small{--uk-translate-x:10px}.uk-transition-slide-top-medium{--uk-translate-y:calc(-1 * 50px)}.uk-transition-slide-bottom-medium{--uk-translate-y:50px}.uk-transition-slide-left-medium{--uk-translate-x:calc(-1 * 50px)}.uk-transition-slide-right-medium{--uk-translate-x:50px}.uk-transition-active.uk-active [class*=uk-transition-slide],.uk-transition-toggle:focus [class*=uk-transition-slide],.uk-transition-toggle:focus-within [class*=uk-transition-slide],.uk-transition-toggle:hover [class*=uk-transition-slide]{--uk-translate-x:0;--uk-translate-y:0;opacity:1}.uk-transition-opaque{opacity:1}.uk-transition-slow{transition-duration:.7s}.uk-transition-disable,.uk-transition-disable *{transition:none!important}.uk-hidden,.uk-hidden-empty:empty,[hidden]{display:none!important}@media (min-width:640px){.uk-hidden\@s{display:none!important}}@media (min-width:960px){.uk-hidden\@m{display:none!important}}@media (min-width:1200px){.uk-hidden\@l{display:none!important}}@media (min-width:1600px){.uk-hidden\@xl{display:none!important}}@media (max-width:639px){.uk-visible\@s{display:none!important}}@media (max-width:959px){.uk-visible\@m{display:none!important}}@media (max-width:1199px){.uk-visible\@l{display:none!important}}@media (max-width:1599px){.uk-visible\@xl{display:none!important}}.uk-invisible{visibility:hidden!important}.uk-hidden-visually:not(:focus):not(:active):not(:focus-within),.uk-visible-toggle:not(:hover):not(:focus) .uk-hidden-hover:not(:focus-visible):not(:has(:focus-visible)),.uk-visible-toggle:not(:hover):not(:focus) .uk-hidden-hover:not(:focus-within){position:absolute!important;width:0!important;height:0!important;padding:0!important;border:0!important;margin:0!important;overflow:hidden!important}.uk-visible-toggle:not(:hover):not(:focus) .uk-invisible-hover:not(:focus-within){opacity:0!important}@media (hover:none){.uk-hidden-touch{display:none!important}}@media (hover){.uk-hidden-notouch{display:none!important}}.uk-card-primary.uk-card-body,.uk-card-primary>:not([class*=uk-card-media]),.uk-card-secondary.uk-card-body,.uk-card-secondary>:not([class*=uk-card-media]),.uk-light,.uk-offcanvas-bar,.uk-overlay-primary,.uk-section-primary:not(.uk-preserve-color),.uk-section-secondary:not(.uk-preserve-color),.uk-tile-primary:not(.uk-preserve-color),.uk-tile-secondary:not(.uk-preserve-color){color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-link,.uk-card-primary.uk-card-body a,.uk-card-primary>:not([class*=uk-card-media]) .uk-link,.uk-card-primary>:not([class*=uk-card-media]) a,.uk-card-secondary.uk-card-body .uk-link,.uk-card-secondary.uk-card-body a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link,.uk-card-secondary>:not([class*=uk-card-media]) a,.uk-light .uk-link,.uk-light a,.uk-offcanvas-bar .uk-link,.uk-offcanvas-bar a,.uk-overlay-primary .uk-link,.uk-overlay-primary a,.uk-section-primary:not(.uk-preserve-color) .uk-link,.uk-section-primary:not(.uk-preserve-color) a,.uk-section-secondary:not(.uk-preserve-color) .uk-link,.uk-section-secondary:not(.uk-preserve-color) a,.uk-tile-primary:not(.uk-preserve-color) .uk-link,.uk-tile-primary:not(.uk-preserve-color) a,.uk-tile-secondary:not(.uk-preserve-color) .uk-link,.uk-tile-secondary:not(.uk-preserve-color) a{color:#fff}.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link,.uk-card-primary.uk-card-body .uk-link:hover,.uk-card-primary.uk-card-body a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-link:hover,.uk-card-primary>:not([class*=uk-card-media]) a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link,.uk-card-secondary.uk-card-body .uk-link:hover,.uk-card-secondary.uk-card-body a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) a:hover,.uk-light .uk-link-toggle:hover .uk-link,.uk-light .uk-link:hover,.uk-light a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link,.uk-offcanvas-bar .uk-link:hover,.uk-offcanvas-bar a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link,.uk-overlay-primary .uk-link:hover,.uk-overlay-primary a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-section-primary:not(.uk-preserve-color) .uk-link:hover,.uk-section-primary:not(.uk-preserve-color) a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-section-secondary:not(.uk-preserve-color) .uk-link:hover,.uk-section-secondary:not(.uk-preserve-color) a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-tile-primary:not(.uk-preserve-color) .uk-link:hover,.uk-tile-primary:not(.uk-preserve-color) a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-link:hover,.uk-tile-secondary:not(.uk-preserve-color) a:hover{color:#fff}.uk-card-primary.uk-card-body :not(pre)>code,.uk-card-primary.uk-card-body :not(pre)>kbd,.uk-card-primary.uk-card-body :not(pre)>samp,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>code,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>kbd,.uk-card-primary>:not([class*=uk-card-media]) :not(pre)>samp,.uk-card-secondary.uk-card-body :not(pre)>code,.uk-card-secondary.uk-card-body :not(pre)>kbd,.uk-card-secondary.uk-card-body :not(pre)>samp,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>code,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>kbd,.uk-card-secondary>:not([class*=uk-card-media]) :not(pre)>samp,.uk-light :not(pre)>code,.uk-light :not(pre)>kbd,.uk-light :not(pre)>samp,.uk-offcanvas-bar :not(pre)>code,.uk-offcanvas-bar :not(pre)>kbd,.uk-offcanvas-bar :not(pre)>samp,.uk-overlay-primary :not(pre)>code,.uk-overlay-primary :not(pre)>kbd,.uk-overlay-primary :not(pre)>samp,.uk-section-primary:not(.uk-preserve-color) :not(pre)>code,.uk-section-primary:not(.uk-preserve-color) :not(pre)>kbd,.uk-section-primary:not(.uk-preserve-color) :not(pre)>samp,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>code,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>kbd,.uk-section-secondary:not(.uk-preserve-color) :not(pre)>samp,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>code,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>kbd,.uk-tile-primary:not(.uk-preserve-color) :not(pre)>samp,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>code,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>kbd,.uk-tile-secondary:not(.uk-preserve-color) :not(pre)>samp{color:rgba(255,255,255,.7);background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body em,.uk-card-primary>:not([class*=uk-card-media]) em,.uk-card-secondary.uk-card-body em,.uk-card-secondary>:not([class*=uk-card-media]) em,.uk-light em,.uk-offcanvas-bar em,.uk-overlay-primary em,.uk-section-primary:not(.uk-preserve-color) em,.uk-section-secondary:not(.uk-preserve-color) em,.uk-tile-primary:not(.uk-preserve-color) em,.uk-tile-secondary:not(.uk-preserve-color) em{color:#fff}.uk-card-primary.uk-card-body .uk-h1,.uk-card-primary.uk-card-body .uk-h2,.uk-card-primary.uk-card-body .uk-h3,.uk-card-primary.uk-card-body .uk-h4,.uk-card-primary.uk-card-body .uk-h5,.uk-card-primary.uk-card-body .uk-h6,.uk-card-primary.uk-card-body .uk-heading-2xlarge,.uk-card-primary.uk-card-body .uk-heading-3xlarge,.uk-card-primary.uk-card-body .uk-heading-large,.uk-card-primary.uk-card-body .uk-heading-medium,.uk-card-primary.uk-card-body .uk-heading-small,.uk-card-primary.uk-card-body .uk-heading-xlarge,.uk-card-primary.uk-card-body h1,.uk-card-primary.uk-card-body h2,.uk-card-primary.uk-card-body h3,.uk-card-primary.uk-card-body h4,.uk-card-primary.uk-card-body h5,.uk-card-primary.uk-card-body h6,.uk-card-primary>:not([class*=uk-card-media]) .uk-h1,.uk-card-primary>:not([class*=uk-card-media]) .uk-h2,.uk-card-primary>:not([class*=uk-card-media]) .uk-h3,.uk-card-primary>:not([class*=uk-card-media]) .uk-h4,.uk-card-primary>:not([class*=uk-card-media]) .uk-h5,.uk-card-primary>:not([class*=uk-card-media]) .uk-h6,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-2xlarge,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-3xlarge,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-large,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-medium,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-small,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-xlarge,.uk-card-primary>:not([class*=uk-card-media]) h1,.uk-card-primary>:not([class*=uk-card-media]) h2,.uk-card-primary>:not([class*=uk-card-media]) h3,.uk-card-primary>:not([class*=uk-card-media]) h4,.uk-card-primary>:not([class*=uk-card-media]) h5,.uk-card-primary>:not([class*=uk-card-media]) h6,.uk-card-secondary.uk-card-body .uk-h1,.uk-card-secondary.uk-card-body .uk-h2,.uk-card-secondary.uk-card-body .uk-h3,.uk-card-secondary.uk-card-body .uk-h4,.uk-card-secondary.uk-card-body .uk-h5,.uk-card-secondary.uk-card-body .uk-h6,.uk-card-secondary.uk-card-body .uk-heading-2xlarge,.uk-card-secondary.uk-card-body .uk-heading-3xlarge,.uk-card-secondary.uk-card-body .uk-heading-large,.uk-card-secondary.uk-card-body .uk-heading-medium,.uk-card-secondary.uk-card-body .uk-heading-small,.uk-card-secondary.uk-card-body .uk-heading-xlarge,.uk-card-secondary.uk-card-body h1,.uk-card-secondary.uk-card-body h2,.uk-card-secondary.uk-card-body h3,.uk-card-secondary.uk-card-body h4,.uk-card-secondary.uk-card-body h5,.uk-card-secondary.uk-card-body h6,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h1,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h2,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h3,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h4,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h5,.uk-card-secondary>:not([class*=uk-card-media]) .uk-h6,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-2xlarge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-3xlarge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-large,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-medium,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-small,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-xlarge,.uk-card-secondary>:not([class*=uk-card-media]) h1,.uk-card-secondary>:not([class*=uk-card-media]) h2,.uk-card-secondary>:not([class*=uk-card-media]) h3,.uk-card-secondary>:not([class*=uk-card-media]) h4,.uk-card-secondary>:not([class*=uk-card-media]) h5,.uk-card-secondary>:not([class*=uk-card-media]) h6,.uk-light .uk-h1,.uk-light .uk-h2,.uk-light .uk-h3,.uk-light .uk-h4,.uk-light .uk-h5,.uk-light .uk-h6,.uk-light .uk-heading-2xlarge,.uk-light .uk-heading-3xlarge,.uk-light .uk-heading-large,.uk-light .uk-heading-medium,.uk-light .uk-heading-small,.uk-light .uk-heading-xlarge,.uk-light h1,.uk-light h2,.uk-light h3,.uk-light h4,.uk-light h5,.uk-light h6,.uk-offcanvas-bar .uk-h1,.uk-offcanvas-bar .uk-h2,.uk-offcanvas-bar .uk-h3,.uk-offcanvas-bar .uk-h4,.uk-offcanvas-bar .uk-h5,.uk-offcanvas-bar .uk-h6,.uk-offcanvas-bar .uk-heading-2xlarge,.uk-offcanvas-bar .uk-heading-3xlarge,.uk-offcanvas-bar .uk-heading-large,.uk-offcanvas-bar .uk-heading-medium,.uk-offcanvas-bar .uk-heading-small,.uk-offcanvas-bar .uk-heading-xlarge,.uk-offcanvas-bar h1,.uk-offcanvas-bar h2,.uk-offcanvas-bar h3,.uk-offcanvas-bar h4,.uk-offcanvas-bar h5,.uk-offcanvas-bar h6,.uk-overlay-primary .uk-h1,.uk-overlay-primary .uk-h2,.uk-overlay-primary .uk-h3,.uk-overlay-primary .uk-h4,.uk-overlay-primary .uk-h5,.uk-overlay-primary .uk-h6,.uk-overlay-primary .uk-heading-2xlarge,.uk-overlay-primary .uk-heading-3xlarge,.uk-overlay-primary .uk-heading-large,.uk-overlay-primary .uk-heading-medium,.uk-overlay-primary .uk-heading-small,.uk-overlay-primary .uk-heading-xlarge,.uk-overlay-primary h1,.uk-overlay-primary h2,.uk-overlay-primary h3,.uk-overlay-primary h4,.uk-overlay-primary h5,.uk-overlay-primary h6,.uk-section-primary:not(.uk-preserve-color) .uk-h1,.uk-section-primary:not(.uk-preserve-color) .uk-h2,.uk-section-primary:not(.uk-preserve-color) .uk-h3,.uk-section-primary:not(.uk-preserve-color) .uk-h4,.uk-section-primary:not(.uk-preserve-color) .uk-h5,.uk-section-primary:not(.uk-preserve-color) .uk-h6,.uk-section-primary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-section-primary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-section-primary:not(.uk-preserve-color) .uk-heading-large,.uk-section-primary:not(.uk-preserve-color) .uk-heading-medium,.uk-section-primary:not(.uk-preserve-color) .uk-heading-small,.uk-section-primary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-section-primary:not(.uk-preserve-color) h1,.uk-section-primary:not(.uk-preserve-color) h2,.uk-section-primary:not(.uk-preserve-color) h3,.uk-section-primary:not(.uk-preserve-color) h4,.uk-section-primary:not(.uk-preserve-color) h5,.uk-section-primary:not(.uk-preserve-color) h6,.uk-section-secondary:not(.uk-preserve-color) .uk-h1,.uk-section-secondary:not(.uk-preserve-color) .uk-h2,.uk-section-secondary:not(.uk-preserve-color) .uk-h3,.uk-section-secondary:not(.uk-preserve-color) .uk-h4,.uk-section-secondary:not(.uk-preserve-color) .uk-h5,.uk-section-secondary:not(.uk-preserve-color) .uk-h6,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-large,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-medium,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-small,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-section-secondary:not(.uk-preserve-color) h1,.uk-section-secondary:not(.uk-preserve-color) h2,.uk-section-secondary:not(.uk-preserve-color) h3,.uk-section-secondary:not(.uk-preserve-color) h4,.uk-section-secondary:not(.uk-preserve-color) h5,.uk-section-secondary:not(.uk-preserve-color) h6,.uk-tile-primary:not(.uk-preserve-color) .uk-h1,.uk-tile-primary:not(.uk-preserve-color) .uk-h2,.uk-tile-primary:not(.uk-preserve-color) .uk-h3,.uk-tile-primary:not(.uk-preserve-color) .uk-h4,.uk-tile-primary:not(.uk-preserve-color) .uk-h5,.uk-tile-primary:not(.uk-preserve-color) .uk-h6,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-large,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-medium,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-small,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-tile-primary:not(.uk-preserve-color) h1,.uk-tile-primary:not(.uk-preserve-color) h2,.uk-tile-primary:not(.uk-preserve-color) h3,.uk-tile-primary:not(.uk-preserve-color) h4,.uk-tile-primary:not(.uk-preserve-color) h5,.uk-tile-primary:not(.uk-preserve-color) h6,.uk-tile-secondary:not(.uk-preserve-color) .uk-h1,.uk-tile-secondary:not(.uk-preserve-color) .uk-h2,.uk-tile-secondary:not(.uk-preserve-color) .uk-h3,.uk-tile-secondary:not(.uk-preserve-color) .uk-h4,.uk-tile-secondary:not(.uk-preserve-color) .uk-h5,.uk-tile-secondary:not(.uk-preserve-color) .uk-h6,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-2xlarge,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-3xlarge,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-large,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-medium,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-small,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-xlarge,.uk-tile-secondary:not(.uk-preserve-color) h1,.uk-tile-secondary:not(.uk-preserve-color) h2,.uk-tile-secondary:not(.uk-preserve-color) h3,.uk-tile-secondary:not(.uk-preserve-color) h4,.uk-tile-secondary:not(.uk-preserve-color) h5,.uk-tile-secondary:not(.uk-preserve-color) h6{color:#fff}.uk-card-primary.uk-card-body blockquote,.uk-card-primary>:not([class*=uk-card-media]) blockquote,.uk-card-secondary.uk-card-body blockquote,.uk-card-secondary>:not([class*=uk-card-media]) blockquote,.uk-light blockquote,.uk-offcanvas-bar blockquote,.uk-overlay-primary blockquote,.uk-section-primary:not(.uk-preserve-color) blockquote,.uk-section-secondary:not(.uk-preserve-color) blockquote,.uk-tile-primary:not(.uk-preserve-color) blockquote,.uk-tile-secondary:not(.uk-preserve-color) blockquote{color:#fff}.uk-card-primary.uk-card-body blockquote footer,.uk-card-primary>:not([class*=uk-card-media]) blockquote footer,.uk-card-secondary.uk-card-body blockquote footer,.uk-card-secondary>:not([class*=uk-card-media]) blockquote footer,.uk-light blockquote footer,.uk-offcanvas-bar blockquote footer,.uk-overlay-primary blockquote footer,.uk-section-primary:not(.uk-preserve-color) blockquote footer,.uk-section-secondary:not(.uk-preserve-color) blockquote footer,.uk-tile-primary:not(.uk-preserve-color) blockquote footer,.uk-tile-secondary:not(.uk-preserve-color) blockquote footer{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-hr,.uk-card-primary.uk-card-body hr,.uk-card-primary>:not([class*=uk-card-media]) .uk-hr,.uk-card-primary>:not([class*=uk-card-media]) hr,.uk-card-secondary.uk-card-body .uk-hr,.uk-card-secondary.uk-card-body hr,.uk-card-secondary>:not([class*=uk-card-media]) .uk-hr,.uk-card-secondary>:not([class*=uk-card-media]) hr,.uk-light .uk-hr,.uk-light hr,.uk-offcanvas-bar .uk-hr,.uk-offcanvas-bar hr,.uk-overlay-primary .uk-hr,.uk-overlay-primary hr,.uk-section-primary:not(.uk-preserve-color) .uk-hr,.uk-section-primary:not(.uk-preserve-color) hr,.uk-section-secondary:not(.uk-preserve-color) .uk-hr,.uk-section-secondary:not(.uk-preserve-color) hr,.uk-tile-primary:not(.uk-preserve-color) .uk-hr,.uk-tile-primary:not(.uk-preserve-color) hr,.uk-tile-secondary:not(.uk-preserve-color) .uk-hr,.uk-tile-secondary:not(.uk-preserve-color) hr{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body :focus-visible,.uk-card-primary>:not([class*=uk-card-media]) :focus-visible,.uk-card-secondary.uk-card-body :focus-visible,.uk-card-secondary>:not([class*=uk-card-media]) :focus-visible,.uk-light :focus-visible,.uk-offcanvas-bar :focus-visible,.uk-overlay-primary :focus-visible,.uk-section-primary:not(.uk-preserve-color) :focus-visible,.uk-section-secondary:not(.uk-preserve-color) :focus-visible,.uk-tile-primary:not(.uk-preserve-color) :focus-visible,.uk-tile-secondary:not(.uk-preserve-color) :focus-visible{outline-color:#fff}.uk-card-primary.uk-card-body .uk-link-muted a,.uk-card-primary.uk-card-body a.uk-link-muted,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted a,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-muted,.uk-card-secondary.uk-card-body .uk-link-muted a,.uk-card-secondary.uk-card-body a.uk-link-muted,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted a,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-muted,.uk-light .uk-link-muted a,.uk-light a.uk-link-muted,.uk-offcanvas-bar .uk-link-muted a,.uk-offcanvas-bar a.uk-link-muted,.uk-overlay-primary .uk-link-muted a,.uk-overlay-primary a.uk-link-muted,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted a,.uk-section-primary:not(.uk-preserve-color) a.uk-link-muted,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted a,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-muted,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted a,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-muted,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted a,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-muted{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-link-muted a:hover,.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link-muted,.uk-card-primary.uk-card-body a.uk-link-muted:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-muted a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-muted,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-muted:hover,.uk-card-secondary.uk-card-body .uk-link-muted a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link-muted,.uk-card-secondary.uk-card-body a.uk-link-muted:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-muted a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-muted,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-muted:hover,.uk-light .uk-link-muted a:hover,.uk-light .uk-link-toggle:hover .uk-link-muted,.uk-light a.uk-link-muted:hover,.uk-offcanvas-bar .uk-link-muted a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link-muted,.uk-offcanvas-bar a.uk-link-muted:hover,.uk-overlay-primary .uk-link-muted a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link-muted,.uk-overlay-primary a.uk-link-muted:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-section-primary:not(.uk-preserve-color) a.uk-link-muted:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-muted:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-muted:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-muted a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-muted,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-muted:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-link-text a:hover,.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link-text,.uk-card-primary.uk-card-body a.uk-link-text:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-text a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-text,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-text:hover,.uk-card-secondary.uk-card-body .uk-link-text a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link-text,.uk-card-secondary.uk-card-body a.uk-link-text:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-text a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-text,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-text:hover,.uk-light .uk-link-text a:hover,.uk-light .uk-link-toggle:hover .uk-link-text,.uk-light a.uk-link-text:hover,.uk-offcanvas-bar .uk-link-text a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link-text,.uk-offcanvas-bar a.uk-link-text:hover,.uk-overlay-primary .uk-link-text a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link-text,.uk-overlay-primary a.uk-link-text:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-section-primary:not(.uk-preserve-color) a.uk-link-text:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-text:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-text:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-text a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-text,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-text:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-link-heading a:hover,.uk-card-primary.uk-card-body .uk-link-toggle:hover .uk-link-heading,.uk-card-primary.uk-card-body a.uk-link-heading:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-heading a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-heading,.uk-card-primary>:not([class*=uk-card-media]) a.uk-link-heading:hover,.uk-card-secondary.uk-card-body .uk-link-heading a:hover,.uk-card-secondary.uk-card-body .uk-link-toggle:hover .uk-link-heading,.uk-card-secondary.uk-card-body a.uk-link-heading:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-heading a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-link-toggle:hover .uk-link-heading,.uk-card-secondary>:not([class*=uk-card-media]) a.uk-link-heading:hover,.uk-light .uk-link-heading a:hover,.uk-light .uk-link-toggle:hover .uk-link-heading,.uk-light a.uk-link-heading:hover,.uk-offcanvas-bar .uk-link-heading a:hover,.uk-offcanvas-bar .uk-link-toggle:hover .uk-link-heading,.uk-offcanvas-bar a.uk-link-heading:hover,.uk-overlay-primary .uk-link-heading a:hover,.uk-overlay-primary .uk-link-toggle:hover .uk-link-heading,.uk-overlay-primary a.uk-link-heading:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-section-primary:not(.uk-preserve-color) a.uk-link-heading:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-section-secondary:not(.uk-preserve-color) a.uk-link-heading:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-tile-primary:not(.uk-preserve-color) a.uk-link-heading:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-heading a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-link-toggle:hover .uk-link-heading,.uk-tile-secondary:not(.uk-preserve-color) a.uk-link-heading:hover{color:#fff}.uk-card-primary.uk-card-body .uk-heading-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-divider,.uk-card-secondary.uk-card-body .uk-heading-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-divider,.uk-light .uk-heading-divider,.uk-offcanvas-bar .uk-heading-divider,.uk-overlay-primary .uk-heading-divider,.uk-section-primary:not(.uk-preserve-color) .uk-heading-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-divider{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-heading-bullet::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-bullet::before,.uk-card-secondary.uk-card-body .uk-heading-bullet::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-bullet::before,.uk-light .uk-heading-bullet::before,.uk-offcanvas-bar .uk-heading-bullet::before,.uk-overlay-primary .uk-heading-bullet::before,.uk-section-primary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-bullet::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-bullet::before{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-heading-line>::after,.uk-card-primary.uk-card-body .uk-heading-line>::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-line>::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-heading-line>::before,.uk-card-secondary.uk-card-body .uk-heading-line>::after,.uk-card-secondary.uk-card-body .uk-heading-line>::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-line>::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-heading-line>::before,.uk-light .uk-heading-line>::after,.uk-light .uk-heading-line>::before,.uk-offcanvas-bar .uk-heading-line>::after,.uk-offcanvas-bar .uk-heading-line>::before,.uk-overlay-primary .uk-heading-line>::after,.uk-overlay-primary .uk-heading-line>::before,.uk-section-primary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-section-primary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-section-secondary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-tile-primary:not(.uk-preserve-color) .uk-heading-line>::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-line>::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-heading-line>::before{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon,.uk-card-secondary.uk-card-body .uk-divider-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon,.uk-light .uk-divider-icon,.uk-offcanvas-bar .uk-divider-icon,.uk-overlay-primary .uk-divider-icon,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22rgba%28255,%20255,%20255,%200.2%29%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-divider-icon::after,.uk-card-primary.uk-card-body .uk-divider-icon::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-icon::before,.uk-card-secondary.uk-card-body .uk-divider-icon::after,.uk-card-secondary.uk-card-body .uk-divider-icon::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-icon::before,.uk-light .uk-divider-icon::after,.uk-light .uk-divider-icon::before,.uk-offcanvas-bar .uk-divider-icon::after,.uk-offcanvas-bar .uk-divider-icon::before,.uk-overlay-primary .uk-divider-icon::after,.uk-overlay-primary .uk-divider-icon::before,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-section-primary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-icon::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-icon::before{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-small::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-small::after,.uk-card-secondary.uk-card-body .uk-divider-small::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-small::after,.uk-light .uk-divider-small::after,.uk-offcanvas-bar .uk-divider-small::after,.uk-overlay-primary .uk-divider-small::after,.uk-section-primary:not(.uk-preserve-color) .uk-divider-small::after,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-small::after,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-small::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-small::after{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-divider-vertical,.uk-card-primary>:not([class*=uk-card-media]) .uk-divider-vertical,.uk-card-secondary.uk-card-body .uk-divider-vertical,.uk-card-secondary>:not([class*=uk-card-media]) .uk-divider-vertical,.uk-light .uk-divider-vertical,.uk-offcanvas-bar .uk-divider-vertical,.uk-overlay-primary .uk-divider-vertical,.uk-section-primary:not(.uk-preserve-color) .uk-divider-vertical,.uk-section-secondary:not(.uk-preserve-color) .uk-divider-vertical,.uk-tile-primary:not(.uk-preserve-color) .uk-divider-vertical,.uk-tile-secondary:not(.uk-preserve-color) .uk-divider-vertical{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-muted>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-muted>::marker,.uk-card-secondary.uk-card-body .uk-list-muted>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-muted>::marker,.uk-light .uk-list-muted>::marker,.uk-offcanvas-bar .uk-list-muted>::marker,.uk-overlay-primary .uk-list-muted>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-muted>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-muted>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-muted>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-muted>::marker{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-list-emphasis>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-emphasis>::marker,.uk-card-secondary.uk-card-body .uk-list-emphasis>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-emphasis>::marker,.uk-light .uk-list-emphasis>::marker,.uk-offcanvas-bar .uk-list-emphasis>::marker,.uk-overlay-primary .uk-list-emphasis>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-emphasis>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-emphasis>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-emphasis>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-emphasis>::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-primary>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-primary>::marker,.uk-card-secondary.uk-card-body .uk-list-primary>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-primary>::marker,.uk-light .uk-list-primary>::marker,.uk-offcanvas-bar .uk-list-primary>::marker,.uk-overlay-primary .uk-list-primary>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-primary>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-primary>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-primary>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-primary>::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-secondary>::marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-secondary>::marker,.uk-card-secondary.uk-card-body .uk-list-secondary>::marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-secondary>::marker,.uk-light .uk-list-secondary>::marker,.uk-offcanvas-bar .uk-list-secondary>::marker,.uk-overlay-primary .uk-list-secondary>::marker,.uk-section-primary:not(.uk-preserve-color) .uk-list-secondary>::marker,.uk-section-secondary:not(.uk-preserve-color) .uk-list-secondary>::marker,.uk-tile-primary:not(.uk-preserve-color) .uk-list-secondary>::marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-secondary>::marker{color:#fff!important}.uk-card-primary.uk-card-body .uk-list-bullet>::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-list-bullet>::before,.uk-card-secondary.uk-card-body .uk-list-bullet>::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-bullet>::before,.uk-light .uk-list-bullet>::before,.uk-offcanvas-bar .uk-list-bullet>::before,.uk-overlay-primary .uk-list-bullet>::before,.uk-section-primary:not(.uk-preserve-color) .uk-list-bullet>::before,.uk-section-secondary:not(.uk-preserve-color) .uk-list-bullet>::before,.uk-tile-primary:not(.uk-preserve-color) .uk-list-bullet>::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-list-bullet>::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-list-divider>:nth-child(n+2),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-divider>:nth-child(n+2),.uk-card-secondary.uk-card-body .uk-list-divider>:nth-child(n+2),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-divider>:nth-child(n+2),.uk-light .uk-list-divider>:nth-child(n+2),.uk-offcanvas-bar .uk-list-divider>:nth-child(n+2),.uk-overlay-primary .uk-list-divider>:nth-child(n+2),.uk-section-primary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2),.uk-section-secondary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2),.uk-tile-primary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-divider>:nth-child(n+2){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-light .uk-list-striped>:nth-of-type(odd),.uk-offcanvas-bar .uk-list-striped>:nth-of-type(odd),.uk-overlay-primary .uk-list-striped>:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd){border-top-color:rgba(255,255,255,.2);border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-list-striped>:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-list-striped>:nth-of-type(odd),.uk-light .uk-list-striped>:nth-of-type(odd),.uk-offcanvas-bar .uk-list-striped>:nth-of-type(odd),.uk-overlay-primary .uk-list-striped>:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-list-striped>:nth-of-type(odd){background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-table th,.uk-card-primary>:not([class*=uk-card-media]) .uk-table th,.uk-card-secondary.uk-card-body .uk-table th,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table th,.uk-light .uk-table th,.uk-offcanvas-bar .uk-table th,.uk-overlay-primary .uk-table th,.uk-section-primary:not(.uk-preserve-color) .uk-table th,.uk-section-secondary:not(.uk-preserve-color) .uk-table th,.uk-tile-primary:not(.uk-preserve-color) .uk-table th,.uk-tile-secondary:not(.uk-preserve-color) .uk-table th{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-table caption,.uk-card-primary>:not([class*=uk-card-media]) .uk-table caption,.uk-card-secondary.uk-card-body .uk-table caption,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table caption,.uk-light .uk-table caption,.uk-offcanvas-bar .uk-table caption,.uk-overlay-primary .uk-table caption,.uk-section-primary:not(.uk-preserve-color) .uk-table caption,.uk-section-secondary:not(.uk-preserve-color) .uk-table caption,.uk-tile-primary:not(.uk-preserve-color) .uk-table caption,.uk-tile-secondary:not(.uk-preserve-color) .uk-table caption{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-table tbody tr.uk-active,.uk-card-primary.uk-card-body .uk-table>tr.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-table tbody tr.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-table>tr.uk-active,.uk-card-secondary.uk-card-body .uk-table tbody tr.uk-active,.uk-card-secondary.uk-card-body .uk-table>tr.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table tbody tr.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table>tr.uk-active,.uk-light .uk-table tbody tr.uk-active,.uk-light .uk-table>tr.uk-active,.uk-offcanvas-bar .uk-table tbody tr.uk-active,.uk-offcanvas-bar .uk-table>tr.uk-active,.uk-overlay-primary .uk-table tbody tr.uk-active,.uk-overlay-primary .uk-table>tr.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-table>tr.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-table tbody tr.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-table>tr.uk-active{background:rgba(255,255,255,.08)}.uk-card-primary.uk-card-body .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-primary.uk-card-body .uk-table-divider>:not(:first-child)>tr,.uk-card-primary.uk-card-body .uk-table-divider>tr:not(:first-child),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>:not(:first-child)>tr,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-divider>tr:not(:first-child),.uk-card-secondary.uk-card-body .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-secondary.uk-card-body .uk-table-divider>:not(:first-child)>tr,.uk-card-secondary.uk-card-body .uk-table-divider>tr:not(:first-child),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>:first-child>tr:not(:first-child),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>:not(:first-child)>tr,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-divider>tr:not(:first-child),.uk-light .uk-table-divider>:first-child>tr:not(:first-child),.uk-light .uk-table-divider>:not(:first-child)>tr,.uk-light .uk-table-divider>tr:not(:first-child),.uk-offcanvas-bar .uk-table-divider>:first-child>tr:not(:first-child),.uk-offcanvas-bar .uk-table-divider>:not(:first-child)>tr,.uk-offcanvas-bar .uk-table-divider>tr:not(:first-child),.uk-overlay-primary .uk-table-divider>:first-child>tr:not(:first-child),.uk-overlay-primary .uk-table-divider>:not(:first-child)>tr,.uk-overlay-primary .uk-table-divider>tr:not(:first-child),.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-section-primary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-section-secondary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-tile-primary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>:first-child>tr:not(:first-child),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>:not(:first-child)>tr,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-divider>tr:not(:first-child){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-primary.uk-card-body .uk-table-striped>tr:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-secondary.uk-card-body .uk-table-striped>tr:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(odd),.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(odd),.uk-light .uk-table-striped tbody tr:nth-of-type(odd),.uk-light .uk-table-striped>tr:nth-of-type(odd),.uk-offcanvas-bar .uk-table-striped tbody tr:nth-of-type(odd),.uk-offcanvas-bar .uk-table-striped>tr:nth-of-type(odd),.uk-overlay-primary .uk-table-striped tbody tr:nth-of-type(odd),.uk-overlay-primary .uk-table-striped>tr:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-section-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(odd),.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(odd){background:rgba(255,255,255,.1);border-top-color:rgba(255,255,255,.2);border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-table-hover tbody tr:hover,.uk-card-primary.uk-card-body .uk-table-hover>tr:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-hover tbody tr:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-hover>tr:hover,.uk-card-secondary.uk-card-body .uk-table-hover tbody tr:hover,.uk-card-secondary.uk-card-body .uk-table-hover>tr:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-hover tbody tr:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-hover>tr:hover,.uk-light .uk-table-hover tbody tr:hover,.uk-light .uk-table-hover>tr:hover,.uk-offcanvas-bar .uk-table-hover tbody tr:hover,.uk-offcanvas-bar .uk-table-hover>tr:hover,.uk-overlay-primary .uk-table-hover tbody tr:hover,.uk-overlay-primary .uk-table-hover>tr:hover,.uk-section-primary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-section-primary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-table-hover>tr:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-hover tbody tr:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-hover>tr:hover{background:rgba(255,255,255,.08)}.uk-card-primary.uk-card-body .uk-icon-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link,.uk-card-secondary.uk-card-body .uk-icon-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link,.uk-light .uk-icon-link,.uk-offcanvas-bar .uk-icon-link,.uk-overlay-primary .uk-icon-link,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-icon-link:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:hover,.uk-card-secondary.uk-card-body .uk-icon-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:hover,.uk-light .uk-icon-link:hover,.uk-offcanvas-bar .uk-icon-link:hover,.uk-overlay-primary .uk-icon-link:hover,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-active>.uk-icon-link,.uk-card-primary.uk-card-body .uk-icon-link:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-active>.uk-icon-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-link:active,.uk-card-secondary.uk-card-body .uk-active>.uk-icon-link,.uk-card-secondary.uk-card-body .uk-icon-link:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-active>.uk-icon-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-link:active,.uk-light .uk-active>.uk-icon-link,.uk-light .uk-icon-link:active,.uk-offcanvas-bar .uk-active>.uk-icon-link,.uk-offcanvas-bar .uk-icon-link:active,.uk-overlay-primary .uk-active>.uk-icon-link,.uk-overlay-primary .uk-icon-link:active,.uk-section-primary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-section-primary:not(.uk-preserve-color) .uk-icon-link:active,.uk-section-secondary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-link:active,.uk-tile-primary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-link:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-active>.uk-icon-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-link:active{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-icon-button,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button,.uk-card-secondary.uk-card-body .uk-icon-button,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button,.uk-light .uk-icon-button,.uk-offcanvas-bar .uk-icon-button,.uk-overlay-primary .uk-icon-button,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-icon-button:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:hover,.uk-card-secondary.uk-card-body .uk-icon-button:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:hover,.uk-light .uk-icon-button:hover,.uk-offcanvas-bar .uk-icon-button:hover,.uk-overlay-primary .uk-icon-button:hover,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:hover{background-color:rgba(255,255,255,.15);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-icon-button:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-icon-button:active,.uk-card-secondary.uk-card-body .uk-icon-button:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-icon-button:active,.uk-light .uk-icon-button:active,.uk-offcanvas-bar .uk-icon-button:active,.uk-overlay-primary .uk-icon-button:active,.uk-section-primary:not(.uk-preserve-color) .uk-icon-button:active,.uk-section-secondary:not(.uk-preserve-color) .uk-icon-button:active,.uk-tile-primary:not(.uk-preserve-color) .uk-icon-button:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-icon-button:active{background-color:rgba(255,255,255,.2);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-range::-webkit-slider-runnable-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-runnable-track,.uk-card-secondary.uk-card-body .uk-range::-webkit-slider-runnable-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-runnable-track,.uk-light .uk-range::-webkit-slider-runnable-track,.uk-offcanvas-bar .uk-range::-webkit-slider-runnable-track,.uk-overlay-primary .uk-range::-webkit-slider-runnable-track,.uk-section-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-runnable-track{background:rgba(242,242,242,.1)}.uk-card-primary.uk-card-body .uk-range:active::-webkit-slider-runnable-track,.uk-card-primary.uk-card-body .uk-range:focus::-webkit-slider-runnable-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range:active::-webkit-slider-runnable-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range:focus::-webkit-slider-runnable-track,.uk-card-secondary.uk-card-body .uk-range:active::-webkit-slider-runnable-track,.uk-card-secondary.uk-card-body .uk-range:focus::-webkit-slider-runnable-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range:active::-webkit-slider-runnable-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range:focus::-webkit-slider-runnable-track,.uk-light .uk-range:active::-webkit-slider-runnable-track,.uk-light .uk-range:focus::-webkit-slider-runnable-track,.uk-offcanvas-bar .uk-range:active::-webkit-slider-runnable-track,.uk-offcanvas-bar .uk-range:focus::-webkit-slider-runnable-track,.uk-overlay-primary .uk-range:active::-webkit-slider-runnable-track,.uk-overlay-primary .uk-range:focus::-webkit-slider-runnable-track,.uk-section-primary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-section-primary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range:active::-webkit-slider-runnable-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range:focus::-webkit-slider-runnable-track{background:rgba(242,242,242,.15)}.uk-card-primary.uk-card-body .uk-range::-moz-range-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-moz-range-track,.uk-card-secondary.uk-card-body .uk-range::-moz-range-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-moz-range-track,.uk-light .uk-range::-moz-range-track,.uk-offcanvas-bar .uk-range::-moz-range-track,.uk-overlay-primary .uk-range::-moz-range-track,.uk-section-primary:not(.uk-preserve-color) .uk-range::-moz-range-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-moz-range-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-moz-range-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-moz-range-track{background:rgba(242,242,242,.1)}.uk-card-primary.uk-card-body .uk-range:focus::-moz-range-track,.uk-card-primary>:not([class*=uk-card-media]) .uk-range:focus::-moz-range-track,.uk-card-secondary.uk-card-body .uk-range:focus::-moz-range-track,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range:focus::-moz-range-track,.uk-light .uk-range:focus::-moz-range-track,.uk-offcanvas-bar .uk-range:focus::-moz-range-track,.uk-overlay-primary .uk-range:focus::-moz-range-track,.uk-section-primary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track,.uk-section-secondary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track,.uk-tile-primary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track,.uk-tile-secondary:not(.uk-preserve-color) .uk-range:focus::-moz-range-track{background:rgba(242,242,242,.15)}.uk-card-primary.uk-card-body .uk-range::-webkit-slider-thumb,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-thumb,.uk-card-secondary.uk-card-body .uk-range::-webkit-slider-thumb,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-webkit-slider-thumb,.uk-light .uk-range::-webkit-slider-thumb,.uk-offcanvas-bar .uk-range::-webkit-slider-thumb,.uk-overlay-primary .uk-range::-webkit-slider-thumb,.uk-section-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-webkit-slider-thumb{background:grey;border-color:#e6e6e6}.uk-card-primary.uk-card-body .uk-range::-moz-range-thumb,.uk-card-primary>:not([class*=uk-card-media]) .uk-range::-moz-range-thumb,.uk-card-secondary.uk-card-body .uk-range::-moz-range-thumb,.uk-card-secondary>:not([class*=uk-card-media]) .uk-range::-moz-range-thumb,.uk-light .uk-range::-moz-range-thumb,.uk-offcanvas-bar .uk-range::-moz-range-thumb,.uk-overlay-primary .uk-range::-moz-range-thumb,.uk-section-primary:not(.uk-preserve-color) .uk-range::-moz-range-thumb,.uk-section-secondary:not(.uk-preserve-color) .uk-range::-moz-range-thumb,.uk-tile-primary:not(.uk-preserve-color) .uk-range::-moz-range-thumb,.uk-tile-secondary:not(.uk-preserve-color) .uk-range::-moz-range-thumb{background:grey;border-color:#e6e6e6}.uk-card-primary.uk-card-body .uk-input,.uk-card-primary.uk-card-body .uk-select,.uk-card-primary.uk-card-body .uk-textarea,.uk-card-primary>:not([class*=uk-card-media]) .uk-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-select,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea,.uk-card-secondary.uk-card-body .uk-input,.uk-card-secondary.uk-card-body .uk-select,.uk-card-secondary.uk-card-body .uk-textarea,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-select,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea,.uk-light .uk-input,.uk-light .uk-select,.uk-light .uk-textarea,.uk-offcanvas-bar .uk-input,.uk-offcanvas-bar .uk-select,.uk-offcanvas-bar .uk-textarea,.uk-overlay-primary .uk-input,.uk-overlay-primary .uk-select,.uk-overlay-primary .uk-textarea,.uk-section-primary:not(.uk-preserve-color) .uk-input,.uk-section-primary:not(.uk-preserve-color) .uk-select,.uk-section-primary:not(.uk-preserve-color) .uk-textarea,.uk-section-secondary:not(.uk-preserve-color) .uk-input,.uk-section-secondary:not(.uk-preserve-color) .uk-select,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea,.uk-tile-primary:not(.uk-preserve-color) .uk-input,.uk-tile-primary:not(.uk-preserve-color) .uk-select,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea,.uk-tile-secondary:not(.uk-preserve-color) .uk-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-select,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7);background-clip:padding-box;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-input:focus,.uk-card-primary.uk-card-body .uk-select:focus,.uk-card-primary.uk-card-body .uk-textarea:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-select:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea:focus,.uk-card-secondary.uk-card-body .uk-input:focus,.uk-card-secondary.uk-card-body .uk-select:focus,.uk-card-secondary.uk-card-body .uk-textarea:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-select:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea:focus,.uk-light .uk-input:focus,.uk-light .uk-select:focus,.uk-light .uk-textarea:focus,.uk-offcanvas-bar .uk-input:focus,.uk-offcanvas-bar .uk-select:focus,.uk-offcanvas-bar .uk-textarea:focus,.uk-overlay-primary .uk-input:focus,.uk-overlay-primary .uk-select:focus,.uk-overlay-primary .uk-textarea:focus,.uk-section-primary:not(.uk-preserve-color) .uk-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-select:focus,.uk-section-primary:not(.uk-preserve-color) .uk-textarea:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-select:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-select:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-select:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea:focus{background-color:rgba(255,255,255,.15);color:rgba(255,255,255,.7);border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-input::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-input::placeholder,.uk-card-secondary.uk-card-body .uk-input::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input::placeholder,.uk-light .uk-input::placeholder,.uk-offcanvas-bar .uk-input::placeholder,.uk-overlay-primary .uk-input::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-input::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-input::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-input::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-input::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-textarea::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-textarea::placeholder,.uk-card-secondary.uk-card-body .uk-textarea::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-textarea::placeholder,.uk-light .uk-textarea::placeholder,.uk-offcanvas-bar .uk-textarea::placeholder,.uk-overlay-primary .uk-textarea::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-textarea::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-textarea::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-select:not([multiple]):not([size]),.uk-card-primary>:not([class*=uk-card-media]) .uk-select:not([multiple]):not([size]),.uk-card-secondary.uk-card-body .uk-select:not([multiple]):not([size]),.uk-card-secondary>:not([class*=uk-card-media]) .uk-select:not([multiple]):not([size]),.uk-light .uk-select:not([multiple]):not([size]),.uk-offcanvas-bar .uk-select:not([multiple]):not([size]),.uk-overlay-primary .uk-select:not([multiple]):not([size]),.uk-section-primary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-section-secondary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-tile-primary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]),.uk-tile-secondary:not(.uk-preserve-color) .uk-select:not([multiple]):not([size]){background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-input[list]:focus,.uk-card-primary.uk-card-body .uk-input[list]:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-input[list]:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-input[list]:hover,.uk-card-secondary.uk-card-body .uk-input[list]:focus,.uk-card-secondary.uk-card-body .uk-input[list]:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input[list]:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-input[list]:hover,.uk-light .uk-input[list]:focus,.uk-light .uk-input[list]:hover,.uk-offcanvas-bar .uk-input[list]:focus,.uk-offcanvas-bar .uk-input[list]:hover,.uk-overlay-primary .uk-input[list]:focus,.uk-overlay-primary .uk-input[list]:hover,.uk-section-primary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-section-primary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-input[list]:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-input[list]:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-input[list]:hover{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-checkbox,.uk-card-primary.uk-card-body .uk-radio,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio,.uk-card-secondary.uk-card-body .uk-checkbox,.uk-card-secondary.uk-card-body .uk-radio,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio,.uk-light .uk-checkbox,.uk-light .uk-radio,.uk-offcanvas-bar .uk-checkbox,.uk-offcanvas-bar .uk-radio,.uk-overlay-primary .uk-checkbox,.uk-overlay-primary .uk-radio,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox,.uk-section-primary:not(.uk-preserve-color) .uk-radio,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox,.uk-section-secondary:not(.uk-preserve-color) .uk-radio,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox,.uk-tile-primary:not(.uk-preserve-color) .uk-radio,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio{background-color:rgba(255,255,255,.1);border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-checkbox:focus,.uk-card-primary.uk-card-body .uk-radio:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:focus,.uk-card-secondary.uk-card-body .uk-checkbox:focus,.uk-card-secondary.uk-card-body .uk-radio:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:focus,.uk-light .uk-checkbox:focus,.uk-light .uk-radio:focus,.uk-offcanvas-bar .uk-checkbox:focus,.uk-offcanvas-bar .uk-radio:focus,.uk-overlay-primary .uk-checkbox:focus,.uk-overlay-primary .uk-radio:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-section-primary:not(.uk-preserve-color) .uk-radio:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:focus{background-color:rgba(255,255,255,.15);border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-checkbox:checked,.uk-card-primary.uk-card-body .uk-checkbox:indeterminate,.uk-card-primary.uk-card-body .uk-radio:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-card-secondary.uk-card-body .uk-checkbox:checked,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate,.uk-card-secondary.uk-card-body .uk-radio:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-light .uk-checkbox:checked,.uk-light .uk-checkbox:indeterminate,.uk-light .uk-radio:checked,.uk-offcanvas-bar .uk-checkbox:checked,.uk-offcanvas-bar .uk-checkbox:indeterminate,.uk-offcanvas-bar .uk-radio:checked,.uk-overlay-primary .uk-checkbox:checked,.uk-overlay-primary .uk-checkbox:indeterminate,.uk-overlay-primary .uk-radio:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked{background-color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-checkbox:checked:focus,.uk-card-primary.uk-card-body .uk-checkbox:indeterminate:focus,.uk-card-primary.uk-card-body .uk-radio:checked:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked:focus,.uk-card-secondary.uk-card-body .uk-checkbox:checked:focus,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate:focus,.uk-card-secondary.uk-card-body .uk-radio:checked:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked:focus,.uk-light .uk-checkbox:checked:focus,.uk-light .uk-checkbox:indeterminate:focus,.uk-light .uk-radio:checked:focus,.uk-offcanvas-bar .uk-checkbox:checked:focus,.uk-offcanvas-bar .uk-checkbox:indeterminate:focus,.uk-offcanvas-bar .uk-radio:checked:focus,.uk-overlay-primary .uk-checkbox:checked:focus,.uk-overlay-primary .uk-checkbox:indeterminate:focus,.uk-overlay-primary .uk-radio:checked:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked:focus{background-color:#fff}.uk-card-primary.uk-card-body .uk-radio:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-card-secondary.uk-card-body .uk-radio:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-radio:checked,.uk-light .uk-radio:checked,.uk-offcanvas-bar .uk-radio:checked,.uk-overlay-primary .uk-radio:checked,.uk-section-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-radio:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-checkbox:checked,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-card-secondary.uk-card-body .uk-checkbox:checked,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:checked,.uk-light .uk-checkbox:checked,.uk-offcanvas-bar .uk-checkbox:checked,.uk-overlay-primary .uk-checkbox:checked,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:checked,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-card-primary.uk-card-body .uk-checkbox:indeterminate,.uk-card-primary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-card-secondary.uk-card-body .uk-checkbox:indeterminate,.uk-card-secondary>:not([class*=uk-card-media]) .uk-checkbox:indeterminate,.uk-light .uk-checkbox:indeterminate,.uk-offcanvas-bar .uk-checkbox:indeterminate,.uk-overlay-primary .uk-checkbox:indeterminate,.uk-section-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-section-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-primary:not(.uk-preserve-color) .uk-checkbox:indeterminate,.uk-tile-secondary:not(.uk-preserve-color) .uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23666%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-form-label,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-label,.uk-card-secondary.uk-card-body .uk-form-label,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-label,.uk-light .uk-form-label,.uk-offcanvas-bar .uk-form-label,.uk-overlay-primary .uk-form-label,.uk-section-primary:not(.uk-preserve-color) .uk-form-label,.uk-section-secondary:not(.uk-preserve-color) .uk-form-label,.uk-tile-primary:not(.uk-preserve-color) .uk-form-label,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-label{color:#fff}.uk-card-primary.uk-card-body .uk-form-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-icon,.uk-card-secondary.uk-card-body .uk-form-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-icon,.uk-light .uk-form-icon,.uk-offcanvas-bar .uk-form-icon,.uk-overlay-primary .uk-form-icon,.uk-section-primary:not(.uk-preserve-color) .uk-form-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-form-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-form-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-icon{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-form-icon:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-form-icon:hover,.uk-card-secondary.uk-card-body .uk-form-icon:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-form-icon:hover,.uk-light .uk-form-icon:hover,.uk-offcanvas-bar .uk-form-icon:hover,.uk-overlay-primary .uk-form-icon:hover,.uk-section-primary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-form-icon:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-form-icon:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-button-default,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default,.uk-card-secondary.uk-card-body .uk-button-default,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default,.uk-light .uk-button-default,.uk-offcanvas-bar .uk-button-default,.uk-overlay-primary .uk-button-default,.uk-section-primary:not(.uk-preserve-color) .uk-button-default,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default{background-color:transparent;color:#fff;border-color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-button-default:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:hover,.uk-card-secondary.uk-card-body .uk-button-default:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:hover,.uk-light .uk-button-default:hover,.uk-offcanvas-bar .uk-button-default:hover,.uk-overlay-primary .uk-button-default:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:hover{background-color:transparent;color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-button-default.uk-active,.uk-card-primary.uk-card-body .uk-button-default:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-default:active,.uk-card-secondary.uk-card-body .uk-button-default.uk-active,.uk-card-secondary.uk-card-body .uk-button-default:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-default:active,.uk-light .uk-button-default.uk-active,.uk-light .uk-button-default:active,.uk-offcanvas-bar .uk-button-default.uk-active,.uk-offcanvas-bar .uk-button-default:active,.uk-overlay-primary .uk-button-default.uk-active,.uk-overlay-primary .uk-button-default:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-default:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-default:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-default:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-default:active{background-color:transparent;color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-button-primary,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary,.uk-card-secondary.uk-card-body .uk-button-primary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary,.uk-light .uk-button-primary,.uk-offcanvas-bar .uk-button-primary,.uk-overlay-primary .uk-button-primary,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-button-primary:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:hover,.uk-card-secondary.uk-card-body .uk-button-primary:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:hover,.uk-light .uk-button-primary:hover,.uk-offcanvas-bar .uk-button-primary:hover,.uk-overlay-primary .uk-button-primary:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:hover{background-color:#f2f2f2;color:#666}.uk-card-primary.uk-card-body .uk-button-primary.uk-active,.uk-card-primary.uk-card-body .uk-button-primary:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-primary:active,.uk-card-secondary.uk-card-body .uk-button-primary.uk-active,.uk-card-secondary.uk-card-body .uk-button-primary:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-primary:active,.uk-light .uk-button-primary.uk-active,.uk-light .uk-button-primary:active,.uk-offcanvas-bar .uk-button-primary.uk-active,.uk-offcanvas-bar .uk-button-primary:active,.uk-overlay-primary .uk-button-primary.uk-active,.uk-overlay-primary .uk-button-primary:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-primary:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-primary:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-primary:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-primary:active{background-color:#e6e6e6;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary,.uk-card-secondary.uk-card-body .uk-button-secondary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary,.uk-light .uk-button-secondary,.uk-offcanvas-bar .uk-button-secondary,.uk-overlay-primary .uk-button-secondary,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:hover,.uk-card-secondary.uk-card-body .uk-button-secondary:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:hover,.uk-light .uk-button-secondary:hover,.uk-offcanvas-bar .uk-button-secondary:hover,.uk-overlay-primary .uk-button-secondary:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:hover{background-color:#f2f2f2;color:#666}.uk-card-primary.uk-card-body .uk-button-secondary.uk-active,.uk-card-primary.uk-card-body .uk-button-secondary:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary.uk-active,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-secondary:active,.uk-card-secondary.uk-card-body .uk-button-secondary.uk-active,.uk-card-secondary.uk-card-body .uk-button-secondary:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary.uk-active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-secondary:active,.uk-light .uk-button-secondary.uk-active,.uk-light .uk-button-secondary:active,.uk-offcanvas-bar .uk-button-secondary.uk-active,.uk-offcanvas-bar .uk-button-secondary:active,.uk-overlay-primary .uk-button-secondary.uk-active,.uk-overlay-primary .uk-button-secondary:active,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-section-primary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-section-secondary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-tile-primary:not(.uk-preserve-color) .uk-button-secondary:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary.uk-active,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-secondary:active{background-color:#e6e6e6;color:#666}.uk-card-primary.uk-card-body .uk-button-text,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text,.uk-card-secondary.uk-card-body .uk-button-text,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text,.uk-light .uk-button-text,.uk-offcanvas-bar .uk-button-text,.uk-overlay-primary .uk-button-text,.uk-section-primary:not(.uk-preserve-color) .uk-button-text,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text{color:#fff}.uk-card-primary.uk-card-body .uk-button-text::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text::before,.uk-card-secondary.uk-card-body .uk-button-text::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text::before,.uk-light .uk-button-text::before,.uk-offcanvas-bar .uk-button-text::before,.uk-overlay-primary .uk-button-text::before,.uk-section-primary:not(.uk-preserve-color) .uk-button-text::before,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text::before,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text::before{border-bottom-color:#fff}.uk-card-primary.uk-card-body .uk-button-text:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:hover,.uk-card-secondary.uk-card-body .uk-button-text:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:hover,.uk-light .uk-button-text:hover,.uk-offcanvas-bar .uk-button-text:hover,.uk-overlay-primary .uk-button-text:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:hover{color:#fff}.uk-card-primary.uk-card-body .uk-button-text:disabled,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-text:disabled,.uk-card-secondary.uk-card-body .uk-button-text:disabled,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-text:disabled,.uk-light .uk-button-text:disabled,.uk-offcanvas-bar .uk-button-text:disabled,.uk-overlay-primary .uk-button-text:disabled,.uk-section-primary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-section-secondary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-tile-primary:not(.uk-preserve-color) .uk-button-text:disabled,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-text:disabled{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-button-link,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link,.uk-card-secondary.uk-card-body .uk-button-link,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link,.uk-light .uk-button-link,.uk-offcanvas-bar .uk-button-link,.uk-overlay-primary .uk-button-link,.uk-section-primary:not(.uk-preserve-color) .uk-button-link,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link{color:#fff}.uk-card-primary.uk-card-body .uk-button-link:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-button-link:hover,.uk-card-secondary.uk-card-body .uk-button-link:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-button-link:hover,.uk-light .uk-button-link:hover,.uk-offcanvas-bar .uk-button-link:hover,.uk-overlay-primary .uk-button-link:hover,.uk-section-primary:not(.uk-preserve-color) .uk-button-link:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-button-link:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-button-link:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-button-link:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body.uk-card-badge,.uk-card-primary>:not([class*=uk-card-media]).uk-card-badge,.uk-card-secondary.uk-card-body.uk-card-badge,.uk-card-secondary>:not([class*=uk-card-media]).uk-card-badge,.uk-light.uk-card-badge,.uk-offcanvas-bar.uk-card-badge,.uk-overlay-primary.uk-card-badge,.uk-section-primary:not(.uk-preserve-color).uk-card-badge,.uk-section-secondary:not(.uk-preserve-color).uk-card-badge,.uk-tile-primary:not(.uk-preserve-color).uk-card-badge,.uk-tile-secondary:not(.uk-preserve-color).uk-card-badge{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-close,.uk-card-primary>:not([class*=uk-card-media]) .uk-close,.uk-card-secondary.uk-card-body .uk-close,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close,.uk-light .uk-close,.uk-offcanvas-bar .uk-close,.uk-overlay-primary .uk-close,.uk-section-primary:not(.uk-preserve-color) .uk-close,.uk-section-secondary:not(.uk-preserve-color) .uk-close,.uk-tile-primary:not(.uk-preserve-color) .uk-close,.uk-tile-secondary:not(.uk-preserve-color) .uk-close{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-close:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-close:hover,.uk-card-secondary.uk-card-body .uk-close:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-close:hover,.uk-light .uk-close:hover,.uk-offcanvas-bar .uk-close:hover,.uk-overlay-primary .uk-close:hover,.uk-section-primary:not(.uk-preserve-color) .uk-close:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-close:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-close:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-close:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-totop,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop,.uk-card-secondary.uk-card-body .uk-totop,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop,.uk-light .uk-totop,.uk-offcanvas-bar .uk-totop,.uk-overlay-primary .uk-totop,.uk-section-primary:not(.uk-preserve-color) .uk-totop,.uk-section-secondary:not(.uk-preserve-color) .uk-totop,.uk-tile-primary:not(.uk-preserve-color) .uk-totop,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-totop:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:hover,.uk-card-secondary.uk-card-body .uk-totop:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:hover,.uk-light .uk-totop:hover,.uk-offcanvas-bar .uk-totop:hover,.uk-overlay-primary .uk-totop:hover,.uk-section-primary:not(.uk-preserve-color) .uk-totop:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-totop:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-totop:active,.uk-card-secondary.uk-card-body .uk-totop:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-totop:active,.uk-light .uk-totop:active,.uk-offcanvas-bar .uk-totop:active,.uk-overlay-primary .uk-totop:active,.uk-section-primary:not(.uk-preserve-color) .uk-totop:active,.uk-section-secondary:not(.uk-preserve-color) .uk-totop:active,.uk-tile-primary:not(.uk-preserve-color) .uk-totop:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-totop:active{color:#fff}.uk-card-primary.uk-card-body .uk-marker,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker,.uk-card-secondary.uk-card-body .uk-marker,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker,.uk-light .uk-marker,.uk-offcanvas-bar .uk-marker,.uk-overlay-primary .uk-marker,.uk-section-primary:not(.uk-preserve-color) .uk-marker,.uk-section-secondary:not(.uk-preserve-color) .uk-marker,.uk-tile-primary:not(.uk-preserve-color) .uk-marker,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker{background:#f8f8f8;color:#666}.uk-card-primary.uk-card-body .uk-marker:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-marker:hover,.uk-card-secondary.uk-card-body .uk-marker:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-marker:hover,.uk-light .uk-marker:hover,.uk-offcanvas-bar .uk-marker:hover,.uk-overlay-primary .uk-marker:hover,.uk-section-primary:not(.uk-preserve-color) .uk-marker:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-marker:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-marker:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-marker:hover{color:#666}.uk-card-primary.uk-card-body .uk-badge,.uk-card-primary>:not([class*=uk-card-media]) .uk-badge,.uk-card-secondary.uk-card-body .uk-badge,.uk-card-secondary>:not([class*=uk-card-media]) .uk-badge,.uk-light .uk-badge,.uk-offcanvas-bar .uk-badge,.uk-overlay-primary .uk-badge,.uk-section-primary:not(.uk-preserve-color) .uk-badge,.uk-section-secondary:not(.uk-preserve-color) .uk-badge,.uk-tile-primary:not(.uk-preserve-color) .uk-badge,.uk-tile-secondary:not(.uk-preserve-color) .uk-badge{background-color:#fff;color:#666!important}.uk-card-primary.uk-card-body .uk-label,.uk-card-primary>:not([class*=uk-card-media]) .uk-label,.uk-card-secondary.uk-card-body .uk-label,.uk-card-secondary>:not([class*=uk-card-media]) .uk-label,.uk-light .uk-label,.uk-offcanvas-bar .uk-label,.uk-overlay-primary .uk-label,.uk-section-primary:not(.uk-preserve-color) .uk-label,.uk-section-secondary:not(.uk-preserve-color) .uk-label,.uk-tile-primary:not(.uk-preserve-color) .uk-label,.uk-tile-secondary:not(.uk-preserve-color) .uk-label{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-article-meta,.uk-card-primary>:not([class*=uk-card-media]) .uk-article-meta,.uk-card-secondary.uk-card-body .uk-article-meta,.uk-card-secondary>:not([class*=uk-card-media]) .uk-article-meta,.uk-light .uk-article-meta,.uk-offcanvas-bar .uk-article-meta,.uk-overlay-primary .uk-article-meta,.uk-section-primary:not(.uk-preserve-color) .uk-article-meta,.uk-section-secondary:not(.uk-preserve-color) .uk-article-meta,.uk-tile-primary:not(.uk-preserve-color) .uk-article-meta,.uk-tile-secondary:not(.uk-preserve-color) .uk-article-meta{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input,.uk-light .uk-search-input,.uk-offcanvas-bar .uk-search-input,.uk-overlay-primary .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-search-input::placeholder,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-input::placeholder,.uk-card-secondary.uk-card-body .uk-search-input::placeholder,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-input::placeholder,.uk-light .uk-search-input::placeholder,.uk-offcanvas-bar .uk-search-input::placeholder,.uk-overlay-primary .uk-search-input::placeholder,.uk-section-primary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-section-secondary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-tile-primary:not(.uk-preserve-color) .uk-search-input::placeholder,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-input::placeholder{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search .uk-search-icon,.uk-card-primary>:not([class*=uk-card-media]) .uk-search .uk-search-icon,.uk-card-secondary.uk-card-body .uk-search .uk-search-icon,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search .uk-search-icon,.uk-light .uk-search .uk-search-icon,.uk-offcanvas-bar .uk-search .uk-search-icon,.uk-overlay-primary .uk-search .uk-search-icon,.uk-section-primary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-section-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-tile-primary:not(.uk-preserve-color) .uk-search .uk-search-icon,.uk-tile-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search .uk-search-icon:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-search .uk-search-icon:hover,.uk-card-secondary.uk-card-body .uk-search .uk-search-icon:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search .uk-search-icon:hover,.uk-light .uk-search .uk-search-icon:hover,.uk-offcanvas-bar .uk-search .uk-search-icon:hover,.uk-overlay-primary .uk-search .uk-search-icon:hover,.uk-section-primary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-search .uk-search-icon:hover{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-default .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-default .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input,.uk-light .uk-search-default .uk-search-input,.uk-offcanvas-bar .uk-search-default .uk-search-input,.uk-overlay-primary .uk-search-default .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-default .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-default .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-default .uk-search-input:focus,.uk-light .uk-search-default .uk-search-input:focus,.uk-offcanvas-bar .uk-search-default .uk-search-input:focus,.uk-overlay-primary .uk-search-default .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-default .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-navbar .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-navbar .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input,.uk-light .uk-search-navbar .uk-search-input,.uk-offcanvas-bar .uk-search-navbar .uk-search-input,.uk-overlay-primary .uk-search-navbar .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-navbar .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-navbar .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-navbar .uk-search-input:focus,.uk-light .uk-search-navbar .uk-search-input:focus,.uk-offcanvas-bar .uk-search-navbar .uk-search-input:focus,.uk-overlay-primary .uk-search-navbar .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-navbar .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-medium .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-medium .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input,.uk-light .uk-search-medium .uk-search-input,.uk-offcanvas-bar .uk-search-medium .uk-search-input,.uk-overlay-primary .uk-search-medium .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-medium .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-medium .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-medium .uk-search-input:focus,.uk-light .uk-search-medium .uk-search-input:focus,.uk-offcanvas-bar .uk-search-medium .uk-search-input:focus,.uk-overlay-primary .uk-search-medium .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-medium .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-large .uk-search-input,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input,.uk-card-secondary.uk-card-body .uk-search-large .uk-search-input,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input,.uk-light .uk-search-large .uk-search-input,.uk-offcanvas-bar .uk-search-large .uk-search-input,.uk-overlay-primary .uk-search-large .uk-search-input,.uk-section-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-section-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-tile-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input{background-color:transparent;border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-search-large .uk-search-input:focus,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input:focus,.uk-card-secondary.uk-card-body .uk-search-large .uk-search-input:focus,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-large .uk-search-input:focus,.uk-light .uk-search-large .uk-search-input:focus,.uk-offcanvas-bar .uk-search-large .uk-search-input:focus,.uk-overlay-primary .uk-search-large .uk-search-input:focus,.uk-section-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus,.uk-section-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus,.uk-tile-primary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-large .uk-search-input:focus{background-color:rgba(0,0,0,.05)}.uk-card-primary.uk-card-body .uk-search-toggle,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle,.uk-card-secondary.uk-card-body .uk-search-toggle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle,.uk-light .uk-search-toggle,.uk-offcanvas-bar .uk-search-toggle,.uk-overlay-primary .uk-search-toggle,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-search-toggle:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-search-toggle:hover,.uk-card-secondary.uk-card-body .uk-search-toggle:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-search-toggle:hover,.uk-light .uk-search-toggle:hover,.uk-offcanvas-bar .uk-search-toggle:hover,.uk-overlay-primary .uk-search-toggle:hover,.uk-section-primary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-search-toggle:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-search-toggle:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-accordion-title,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title,.uk-card-secondary.uk-card-body .uk-accordion-title,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title,.uk-light .uk-accordion-title,.uk-offcanvas-bar .uk-accordion-title,.uk-overlay-primary .uk-accordion-title,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title{color:#fff}.uk-card-primary.uk-card-body .uk-accordion-title:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title:hover,.uk-card-secondary.uk-card-body .uk-accordion-title:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title:hover,.uk-light .uk-accordion-title:hover,.uk-offcanvas-bar .uk-accordion-title:hover,.uk-overlay-primary .uk-accordion-title:hover,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-thumbnav>*>::after,.uk-card-primary>:not([class*=uk-card-media]) .uk-thumbnav>*>::after,.uk-card-secondary.uk-card-body .uk-thumbnav>*>::after,.uk-card-secondary>:not([class*=uk-card-media]) .uk-thumbnav>*>::after,.uk-light .uk-thumbnav>*>::after,.uk-offcanvas-bar .uk-thumbnav>*>::after,.uk-overlay-primary .uk-thumbnav>*>::after,.uk-section-primary:not(.uk-preserve-color) .uk-thumbnav>*>::after,.uk-section-secondary:not(.uk-preserve-color) .uk-thumbnav>*>::after,.uk-tile-primary:not(.uk-preserve-color) .uk-thumbnav>*>::after,.uk-tile-secondary:not(.uk-preserve-color) .uk-thumbnav>*>::after{background-image:linear-gradient(180deg,rgba(0,0,0,0),rgba(0,0,0,.4))}.uk-card-primary.uk-card-body .uk-iconnav>*>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a,.uk-card-secondary.uk-card-body .uk-iconnav>*>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a,.uk-light .uk-iconnav>*>a,.uk-offcanvas-bar .uk-iconnav>*>a,.uk-overlay-primary .uk-iconnav>*>a,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-iconnav>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>*>a:hover,.uk-card-secondary.uk-card-body .uk-iconnav>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>*>a:hover,.uk-light .uk-iconnav>*>a:hover,.uk-offcanvas-bar .uk-iconnav>*>a:hover,.uk-overlay-primary .uk-iconnav>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-iconnav>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-iconnav>.uk-active>a,.uk-card-secondary.uk-card-body .uk-iconnav>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-iconnav>.uk-active>a,.uk-light .uk-iconnav>.uk-active>a,.uk-offcanvas-bar .uk-iconnav>.uk-active>a,.uk-overlay-primary .uk-iconnav>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-iconnav>.uk-active>a{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-grid-divider>:not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-grid-divider>:not(.uk-first-column)::before,.uk-light .uk-grid-divider>:not(.uk-first-column)::before,.uk-offcanvas-bar .uk-grid-divider>:not(.uk-first-column)::before,.uk-overlay-primary .uk-grid-divider>:not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-grid-divider>:not(.uk-first-column)::before{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-secondary.uk-card-body .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-light .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-offcanvas-bar .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-overlay-primary .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-section-primary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-section-secondary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-tile-primary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-default>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a,.uk-card-secondary.uk-card-body .uk-nav-default>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a,.uk-light .uk-nav-default>li>a,.uk-offcanvas-bar .uk-nav-default>li>a,.uk-overlay-primary .uk-nav-default>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-default>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-default>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li>a:hover,.uk-light .uk-nav-default>li>a:hover,.uk-offcanvas-bar .uk-nav-default>li>a:hover,.uk-overlay-primary .uk-nav-default>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-default>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-default>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default>li.uk-active>a,.uk-light .uk-nav-default>li.uk-active>a,.uk-offcanvas-bar .uk-nav-default>li.uk-active>a,.uk-overlay-primary .uk-nav-default>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-header,.uk-light .uk-nav-default .uk-nav-header,.uk-offcanvas-bar .uk-nav-default .uk-nav-header,.uk-overlay-primary .uk-nav-default .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-divider,.uk-light .uk-nav-default .uk-nav-divider,.uk-offcanvas-bar .uk-nav-default .uk-nav-divider,.uk-overlay-primary .uk-nav-default .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a,.uk-light .uk-nav-default .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a,.uk-overlay-primary .uk-nav-default .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub a:hover,.uk-light .uk-nav-default .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-default .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-default .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a,.uk-light .uk-nav-primary>li>a,.uk-offcanvas-bar .uk-nav-primary>li>a,.uk-overlay-primary .uk-nav-primary>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-primary>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-primary>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li>a:hover,.uk-light .uk-nav-primary>li>a:hover,.uk-offcanvas-bar .uk-nav-primary>li>a:hover,.uk-overlay-primary .uk-nav-primary>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-primary>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-primary>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary>li.uk-active>a,.uk-light .uk-nav-primary>li.uk-active>a,.uk-offcanvas-bar .uk-nav-primary>li.uk-active>a,.uk-overlay-primary .uk-nav-primary>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-header,.uk-light .uk-nav-primary .uk-nav-header,.uk-offcanvas-bar .uk-nav-primary .uk-nav-header,.uk-overlay-primary .uk-nav-primary .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-divider,.uk-light .uk-nav-primary .uk-nav-divider,.uk-offcanvas-bar .uk-nav-primary .uk-nav-divider,.uk-overlay-primary .uk-nav-primary .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a,.uk-light .uk-nav-primary .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub a:hover,.uk-light .uk-nav-primary .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-primary .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-primary .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a,.uk-card-secondary.uk-card-body .uk-nav-secondary>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a,.uk-light .uk-nav-secondary>li>a,.uk-offcanvas-bar .uk-nav-secondary>li>a,.uk-overlay-primary .uk-nav-secondary>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary>li>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover,.uk-card-secondary.uk-card-body .uk-nav-secondary>li>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover,.uk-light .uk-nav-secondary>li>a:hover,.uk-offcanvas-bar .uk-nav-secondary>li>a:hover,.uk-overlay-primary .uk-nav-secondary>li>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover{color:#fff;background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-nav-secondary>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-secondary>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a,.uk-light .uk-nav-secondary>li.uk-active>a,.uk-offcanvas-bar .uk-nav-secondary>li.uk-active>a,.uk-overlay-primary .uk-nav-secondary>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a{color:#fff;background-color:rgba(255,255,255,.1)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-subtitle,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-subtitle,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-subtitle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-subtitle,.uk-light .uk-nav-secondary .uk-nav-subtitle,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-subtitle,.uk-overlay-primary .uk-nav-secondary .uk-nav-subtitle,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-subtitle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-card-secondary.uk-card-body .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-light .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-offcanvas-bar .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-overlay-primary .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li>a:hover .uk-nav-subtitle{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-card-secondary.uk-card-body .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-light .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-offcanvas-bar .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-overlay-primary .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary>li.uk-active>a .uk-nav-subtitle{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-header,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-header,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-header,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-header,.uk-light .uk-nav-secondary .uk-nav-header,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-header,.uk-overlay-primary .uk-nav-secondary .uk-nav-header,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-header{color:#fff}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-divider,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-divider,.uk-light .uk-nav-secondary .uk-nav-divider,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-divider,.uk-overlay-primary .uk-nav-secondary .uk-nav-divider,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-divider{border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-sub a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-sub a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a,.uk-light .uk-nav-secondary .uk-nav-sub a,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-sub a,.uk-overlay-primary .uk-nav-secondary .uk-nav-sub a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-sub a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a:hover,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-sub a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub a:hover,.uk-light .uk-nav-secondary .uk-nav-sub a:hover,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-sub a:hover,.uk-overlay-primary .uk-nav-secondary .uk-nav-sub a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-card-secondary.uk-card-body .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-light .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-offcanvas-bar .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-overlay-primary .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-nav-secondary .uk-nav-sub li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-card-primary>:not([class*=uk-card-media]) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-card-secondary.uk-card-body .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-card-secondary>:not([class*=uk-card-media]) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-light .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-offcanvas-bar .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-overlay-primary .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-section-primary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-section-secondary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-tile-primary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider),.uk-tile-secondary:not(.uk-preserve-color) .uk-nav.uk-nav-divider>:not(.uk-nav-divider)+:not(.uk-nav-header,.uk-nav-divider){border-top-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-navbar-nav>li>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a,.uk-light .uk-navbar-nav>li>a,.uk-offcanvas-bar .uk-navbar-nav>li>a,.uk-overlay-primary .uk-navbar-nav>li>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-navbar-nav>li:hover>a,.uk-card-primary.uk-card-body .uk-navbar-nav>li>a[aria-expanded=true],.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li:hover>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a[aria-expanded=true],.uk-card-secondary.uk-card-body .uk-navbar-nav>li:hover>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a[aria-expanded=true],.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li:hover>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a[aria-expanded=true],.uk-light .uk-navbar-nav>li:hover>a,.uk-light .uk-navbar-nav>li>a[aria-expanded=true],.uk-offcanvas-bar .uk-navbar-nav>li:hover>a,.uk-offcanvas-bar .uk-navbar-nav>li>a[aria-expanded=true],.uk-overlay-primary .uk-navbar-nav>li:hover>a,.uk-overlay-primary .uk-navbar-nav>li>a[aria-expanded=true],.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true],.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true],.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true],.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li:hover>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a[aria-expanded=true]{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-navbar-nav>li>a:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:active,.uk-card-secondary.uk-card-body .uk-navbar-nav>li>a:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li>a:active,.uk-light .uk-navbar-nav>li>a:active,.uk-offcanvas-bar .uk-navbar-nav>li>a:active,.uk-overlay-primary .uk-navbar-nav>li>a:active,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li>a:active{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-nav>li.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-nav>li.uk-active>a,.uk-card-secondary.uk-card-body .uk-navbar-nav>li.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-nav>li.uk-active>a,.uk-light .uk-navbar-nav>li.uk-active>a,.uk-offcanvas-bar .uk-navbar-nav>li.uk-active>a,.uk-overlay-primary .uk-navbar-nav>li.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-nav>li.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-navbar-item,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-item,.uk-card-secondary.uk-card-body .uk-navbar-item,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-item,.uk-light .uk-navbar-item,.uk-offcanvas-bar .uk-navbar-item,.uk-overlay-primary .uk-navbar-item,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-item,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-item,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-item,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-item{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-navbar-toggle,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle,.uk-card-secondary.uk-card-body .uk-navbar-toggle,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle,.uk-light .uk-navbar-toggle,.uk-offcanvas-bar .uk-navbar-toggle,.uk-overlay-primary .uk-navbar-toggle,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-navbar-toggle:hover,.uk-card-primary.uk-card-body .uk-navbar-toggle[aria-expanded=true],.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-navbar-toggle[aria-expanded=true],.uk-card-secondary.uk-card-body .uk-navbar-toggle:hover,.uk-card-secondary.uk-card-body .uk-navbar-toggle[aria-expanded=true],.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-navbar-toggle[aria-expanded=true],.uk-light .uk-navbar-toggle:hover,.uk-light .uk-navbar-toggle[aria-expanded=true],.uk-offcanvas-bar .uk-navbar-toggle:hover,.uk-offcanvas-bar .uk-navbar-toggle[aria-expanded=true],.uk-overlay-primary .uk-navbar-toggle:hover,.uk-overlay-primary .uk-navbar-toggle[aria-expanded=true],.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-section-primary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true],.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true],.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true],.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-navbar-toggle[aria-expanded=true]{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav>*>:first-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>:first-child,.uk-card-secondary.uk-card-body .uk-subnav>*>:first-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>:first-child,.uk-light .uk-subnav>*>:first-child,.uk-offcanvas-bar .uk-subnav>*>:first-child,.uk-overlay-primary .uk-subnav>*>:first-child,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>:first-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>:first-child{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-subnav>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>*>a:hover,.uk-card-secondary.uk-card-body .uk-subnav>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>*>a:hover,.uk-light .uk-subnav>*>a:hover,.uk-offcanvas-bar .uk-subnav>*>a:hover,.uk-overlay-primary .uk-subnav>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>.uk-active>a,.uk-card-secondary.uk-card-body .uk-subnav>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>.uk-active>a,.uk-light .uk-subnav>.uk-active>a,.uk-offcanvas-bar .uk-subnav>.uk-active>a,.uk-overlay-primary .uk-subnav>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>.uk-active>a{color:#fff}.uk-card-primary.uk-card-body .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-light .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-offcanvas-bar .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-overlay-primary .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{border-left-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>:first-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>:first-child,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>:first-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>:first-child,.uk-light .uk-subnav-pill>*>:first-child,.uk-offcanvas-bar .uk-subnav-pill>*>:first-child,.uk-overlay-primary .uk-subnav-pill>*>:first-child,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>:first-child{background-color:transparent;color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:hover,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:hover,.uk-light .uk-subnav-pill>*>a:hover,.uk-offcanvas-bar .uk-subnav-pill>*>a:hover,.uk-overlay-primary .uk-subnav-pill>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:hover{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav-pill>*>a:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:active,.uk-card-secondary.uk-card-body .uk-subnav-pill>*>a:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>*>a:active,.uk-light .uk-subnav-pill>*>a:active,.uk-offcanvas-bar .uk-subnav-pill>*>a:active,.uk-overlay-primary .uk-subnav-pill>*>a:active,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>*>a:active{background-color:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-subnav-pill>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav-pill>.uk-active>a,.uk-card-secondary.uk-card-body .uk-subnav-pill>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav-pill>.uk-active>a,.uk-light .uk-subnav-pill>.uk-active>a,.uk-offcanvas-bar .uk-subnav-pill>.uk-active>a,.uk-overlay-primary .uk-subnav-pill>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav-pill>.uk-active>a{background-color:#fff;color:#666}.uk-card-primary.uk-card-body .uk-subnav>.uk-disabled>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-subnav>.uk-disabled>a,.uk-card-secondary.uk-card-body .uk-subnav>.uk-disabled>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-subnav>.uk-disabled>a,.uk-light .uk-subnav>.uk-disabled>a,.uk-offcanvas-bar .uk-subnav>.uk-disabled>a,.uk-overlay-primary .uk-subnav>.uk-disabled>a,.uk-section-primary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-section-secondary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-tile-primary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-subnav>.uk-disabled>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-breadcrumb>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>*,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>*,.uk-light .uk-breadcrumb>*>*,.uk-offcanvas-bar .uk-breadcrumb>*>*,.uk-overlay-primary .uk-breadcrumb>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-breadcrumb>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:hover,.uk-card-secondary.uk-card-body .uk-breadcrumb>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>*>:hover,.uk-light .uk-breadcrumb>*>:hover,.uk-offcanvas-bar .uk-breadcrumb>*>:hover,.uk-overlay-primary .uk-breadcrumb>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>*>:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-breadcrumb>:last-child>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>:last-child>*,.uk-card-secondary.uk-card-body .uk-breadcrumb>:last-child>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>:last-child>*,.uk-light .uk-breadcrumb>:last-child>*,.uk-offcanvas-bar .uk-breadcrumb>:last-child>*,.uk-overlay-primary .uk-breadcrumb>:last-child>*,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>:last-child>*{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary.uk-card-body .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-light .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-offcanvas-bar .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-overlay-primary .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-primary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-section-secondary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-primary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-breadcrumb>:nth-child(n+2):not(.uk-first-column)::before{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-pagination>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>*,.uk-card-secondary.uk-card-body .uk-pagination>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>*,.uk-light .uk-pagination>*>*,.uk-offcanvas-bar .uk-pagination>*>*,.uk-overlay-primary .uk-pagination>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-pagination>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>*>:hover,.uk-card-secondary.uk-card-body .uk-pagination>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>*>:hover,.uk-light .uk-pagination>*>:hover,.uk-offcanvas-bar .uk-pagination>*>:hover,.uk-overlay-primary .uk-pagination>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>*>:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-pagination>.uk-active>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>.uk-active>*,.uk-card-secondary.uk-card-body .uk-pagination>.uk-active>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>.uk-active>*,.uk-light .uk-pagination>.uk-active>*,.uk-offcanvas-bar .uk-pagination>.uk-active>*,.uk-overlay-primary .uk-pagination>.uk-active>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>.uk-active>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>.uk-active>*{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-pagination>.uk-disabled>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-pagination>.uk-disabled>*,.uk-card-secondary.uk-card-body .uk-pagination>.uk-disabled>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-pagination>.uk-disabled>*,.uk-light .uk-pagination>.uk-disabled>*,.uk-offcanvas-bar .uk-pagination>.uk-disabled>*,.uk-overlay-primary .uk-pagination>.uk-disabled>*,.uk-section-primary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-section-secondary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-tile-primary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-pagination>.uk-disabled>*{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-tab::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab::before,.uk-card-secondary.uk-card-body .uk-tab::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab::before,.uk-light .uk-tab::before,.uk-offcanvas-bar .uk-tab::before,.uk-overlay-primary .uk-tab::before,.uk-section-primary:not(.uk-preserve-color) .uk-tab::before,.uk-section-secondary:not(.uk-preserve-color) .uk-tab::before,.uk-tile-primary:not(.uk-preserve-color) .uk-tab::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab::before{border-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-tab>*>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a,.uk-card-secondary.uk-card-body .uk-tab>*>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a,.uk-light .uk-tab>*>a,.uk-offcanvas-bar .uk-tab>*>a,.uk-overlay-primary .uk-tab>*>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-tab>*>a:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>*>a:hover,.uk-card-secondary.uk-card-body .uk-tab>*>a:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>*>a:hover,.uk-light .uk-tab>*>a:hover,.uk-offcanvas-bar .uk-tab>*>a:hover,.uk-overlay-primary .uk-tab>*>a:hover,.uk-section-primary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>*>a:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>*>a:hover{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-tab>.uk-active>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>.uk-active>a,.uk-card-secondary.uk-card-body .uk-tab>.uk-active>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>.uk-active>a,.uk-light .uk-tab>.uk-active>a,.uk-offcanvas-bar .uk-tab>.uk-active>a,.uk-overlay-primary .uk-tab>.uk-active>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>.uk-active>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>.uk-active>a{color:#fff;border-color:#fff}.uk-card-primary.uk-card-body .uk-tab>.uk-disabled>a,.uk-card-primary>:not([class*=uk-card-media]) .uk-tab>.uk-disabled>a,.uk-card-secondary.uk-card-body .uk-tab>.uk-disabled>a,.uk-card-secondary>:not([class*=uk-card-media]) .uk-tab>.uk-disabled>a,.uk-light .uk-tab>.uk-disabled>a,.uk-offcanvas-bar .uk-tab>.uk-disabled>a,.uk-overlay-primary .uk-tab>.uk-disabled>a,.uk-section-primary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-section-secondary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-tile-primary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a,.uk-tile-secondary:not(.uk-preserve-color) .uk-tab>.uk-disabled>a{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-slidenav,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav,.uk-card-secondary.uk-card-body .uk-slidenav,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav,.uk-light .uk-slidenav,.uk-offcanvas-bar .uk-slidenav,.uk-overlay-primary .uk-slidenav,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-slidenav:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:hover,.uk-card-secondary.uk-card-body .uk-slidenav:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:hover,.uk-light .uk-slidenav:hover,.uk-offcanvas-bar .uk-slidenav:hover,.uk-overlay-primary .uk-slidenav:hover,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:hover{color:rgba(255,255,255,.95)}.uk-card-primary.uk-card-body .uk-slidenav:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-slidenav:active,.uk-card-secondary.uk-card-body .uk-slidenav:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-slidenav:active,.uk-light .uk-slidenav:active,.uk-offcanvas-bar .uk-slidenav:active,.uk-overlay-primary .uk-slidenav:active,.uk-section-primary:not(.uk-preserve-color) .uk-slidenav:active,.uk-section-secondary:not(.uk-preserve-color) .uk-slidenav:active,.uk-tile-primary:not(.uk-preserve-color) .uk-slidenav:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-slidenav:active{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-dotnav>*>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>*,.uk-card-secondary.uk-card-body .uk-dotnav>*>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>*,.uk-light .uk-dotnav>*>*,.uk-offcanvas-bar .uk-dotnav>*>*,.uk-overlay-primary .uk-dotnav>*>*,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>*{background-color:transparent;border-color:rgba(255,255,255,.9)}.uk-card-primary.uk-card-body .uk-dotnav>*>:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:hover,.uk-card-secondary.uk-card-body .uk-dotnav>*>:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:hover,.uk-light .uk-dotnav>*>:hover,.uk-offcanvas-bar .uk-dotnav>*>:hover,.uk-overlay-primary .uk-dotnav>*>:hover,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:hover{background-color:rgba(255,255,255,.9);border-color:transparent}.uk-card-primary.uk-card-body .uk-dotnav>*>:active,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>*>:active,.uk-card-secondary.uk-card-body .uk-dotnav>*>:active,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>*>:active,.uk-light .uk-dotnav>*>:active,.uk-offcanvas-bar .uk-dotnav>*>:active,.uk-overlay-primary .uk-dotnav>*>:active,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>*>:active,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>*>:active{background-color:rgba(255,255,255,.5);border-color:transparent}.uk-card-primary.uk-card-body .uk-dotnav>.uk-active>*,.uk-card-primary>:not([class*=uk-card-media]) .uk-dotnav>.uk-active>*,.uk-card-secondary.uk-card-body .uk-dotnav>.uk-active>*,.uk-card-secondary>:not([class*=uk-card-media]) .uk-dotnav>.uk-active>*,.uk-light .uk-dotnav>.uk-active>*,.uk-offcanvas-bar .uk-dotnav>.uk-active>*,.uk-overlay-primary .uk-dotnav>.uk-active>*,.uk-section-primary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-section-secondary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-tile-primary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*,.uk-tile-secondary:not(.uk-preserve-color) .uk-dotnav>.uk-active>*{background-color:rgba(255,255,255,.9);border-color:transparent}.uk-card-primary.uk-card-body .uk-text-lead,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-lead,.uk-card-secondary.uk-card-body .uk-text-lead,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-lead,.uk-light .uk-text-lead,.uk-offcanvas-bar .uk-text-lead,.uk-overlay-primary .uk-text-lead,.uk-section-primary:not(.uk-preserve-color) .uk-text-lead,.uk-section-secondary:not(.uk-preserve-color) .uk-text-lead,.uk-tile-primary:not(.uk-preserve-color) .uk-text-lead,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-lead{color:rgba(255,255,255,.7)}.uk-card-primary.uk-card-body .uk-text-meta,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-meta,.uk-card-secondary.uk-card-body .uk-text-meta,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-meta,.uk-light .uk-text-meta,.uk-offcanvas-bar .uk-text-meta,.uk-overlay-primary .uk-text-meta,.uk-section-primary:not(.uk-preserve-color) .uk-text-meta,.uk-section-secondary:not(.uk-preserve-color) .uk-text-meta,.uk-tile-primary:not(.uk-preserve-color) .uk-text-meta,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-meta{color:rgba(255,255,255,.5)}.uk-card-primary.uk-card-body .uk-text-muted,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-muted,.uk-card-secondary.uk-card-body .uk-text-muted,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-muted,.uk-light .uk-text-muted,.uk-offcanvas-bar .uk-text-muted,.uk-overlay-primary .uk-text-muted,.uk-section-primary:not(.uk-preserve-color) .uk-text-muted,.uk-section-secondary:not(.uk-preserve-color) .uk-text-muted,.uk-tile-primary:not(.uk-preserve-color) .uk-text-muted,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-muted{color:rgba(255,255,255,.5)!important}.uk-card-primary.uk-card-body .uk-text-emphasis,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-emphasis,.uk-card-secondary.uk-card-body .uk-text-emphasis,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-emphasis,.uk-light .uk-text-emphasis,.uk-offcanvas-bar .uk-text-emphasis,.uk-overlay-primary .uk-text-emphasis,.uk-section-primary:not(.uk-preserve-color) .uk-text-emphasis,.uk-section-secondary:not(.uk-preserve-color) .uk-text-emphasis,.uk-tile-primary:not(.uk-preserve-color) .uk-text-emphasis,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-emphasis{color:#fff!important}.uk-card-primary.uk-card-body .uk-text-primary,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-primary,.uk-card-secondary.uk-card-body .uk-text-primary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-primary,.uk-light .uk-text-primary,.uk-offcanvas-bar .uk-text-primary,.uk-overlay-primary .uk-text-primary,.uk-section-primary:not(.uk-preserve-color) .uk-text-primary,.uk-section-secondary:not(.uk-preserve-color) .uk-text-primary,.uk-tile-primary:not(.uk-preserve-color) .uk-text-primary,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-primary{color:#fff!important}.uk-card-primary.uk-card-body .uk-text-secondary,.uk-card-primary>:not([class*=uk-card-media]) .uk-text-secondary,.uk-card-secondary.uk-card-body .uk-text-secondary,.uk-card-secondary>:not([class*=uk-card-media]) .uk-text-secondary,.uk-light .uk-text-secondary,.uk-offcanvas-bar .uk-text-secondary,.uk-overlay-primary .uk-text-secondary,.uk-section-primary:not(.uk-preserve-color) .uk-text-secondary,.uk-section-secondary:not(.uk-preserve-color) .uk-text-secondary,.uk-tile-primary:not(.uk-preserve-color) .uk-text-secondary,.uk-tile-secondary:not(.uk-preserve-color) .uk-text-secondary{color:#fff!important}.uk-card-primary.uk-card-body .uk-column-divider,.uk-card-primary>:not([class*=uk-card-media]) .uk-column-divider,.uk-card-secondary.uk-card-body .uk-column-divider,.uk-card-secondary>:not([class*=uk-card-media]) .uk-column-divider,.uk-light .uk-column-divider,.uk-offcanvas-bar .uk-column-divider,.uk-overlay-primary .uk-column-divider,.uk-section-primary:not(.uk-preserve-color) .uk-column-divider,.uk-section-secondary:not(.uk-preserve-color) .uk-column-divider,.uk-tile-primary:not(.uk-preserve-color) .uk-column-divider,.uk-tile-secondary:not(.uk-preserve-color) .uk-column-divider{column-rule-color:rgba(255,255,255,0.2)}.uk-card-primary.uk-card-body .uk-logo,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo,.uk-card-secondary.uk-card-body .uk-logo,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo,.uk-light .uk-logo,.uk-offcanvas-bar .uk-logo,.uk-overlay-primary .uk-logo,.uk-section-primary:not(.uk-preserve-color) .uk-logo,.uk-section-secondary:not(.uk-preserve-color) .uk-logo,.uk-tile-primary:not(.uk-preserve-color) .uk-logo,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo{color:#fff}.uk-card-primary.uk-card-body .uk-logo:hover,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo:hover,.uk-card-secondary.uk-card-body .uk-logo:hover,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo:hover,.uk-light .uk-logo:hover,.uk-offcanvas-bar .uk-logo:hover,.uk-overlay-primary .uk-logo:hover,.uk-section-primary:not(.uk-preserve-color) .uk-logo:hover,.uk-section-secondary:not(.uk-preserve-color) .uk-logo:hover,.uk-tile-primary:not(.uk-preserve-color) .uk-logo:hover,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo:hover{color:#fff}.uk-card-primary.uk-card-body .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-card-primary>:not([class*=uk-card-media]) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-card-secondary.uk-card-body .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-light .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-offcanvas-bar .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-overlay-primary .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-section-primary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-section-secondary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-tile-primary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse),.uk-tile-secondary:not(.uk-preserve-color) .uk-logo:has(.uk-logo-inverse)>:not(picture:has(.uk-logo-inverse)):not(.uk-logo-inverse){display:none}.uk-card-primary.uk-card-body .uk-logo-inverse,.uk-card-primary>:not([class*=uk-card-media]) .uk-logo-inverse,.uk-card-secondary.uk-card-body .uk-logo-inverse,.uk-card-secondary>:not([class*=uk-card-media]) .uk-logo-inverse,.uk-light .uk-logo-inverse,.uk-offcanvas-bar .uk-logo-inverse,.uk-overlay-primary .uk-logo-inverse,.uk-section-primary:not(.uk-preserve-color) .uk-logo-inverse,.uk-section-secondary:not(.uk-preserve-color) .uk-logo-inverse,.uk-tile-primary:not(.uk-preserve-color) .uk-logo-inverse,.uk-tile-secondary:not(.uk-preserve-color) .uk-logo-inverse{display:block}.uk-card-primary.uk-card-body .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-primary.uk-card-body .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-primary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-card-secondary.uk-card-body .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-secondary.uk-card-body .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-card-secondary>:not([class*=uk-card-media]) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-light .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-light .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-offcanvas-bar .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-offcanvas-bar .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-overlay-primary .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-overlay-primary .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-section-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-section-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-section-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-tile-primary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped tbody tr:nth-of-type(2n):last-child,.uk-tile-secondary:not(.uk-preserve-color) .uk-table-striped>tr:nth-of-type(2n):last-child{border-bottom-color:rgba(255,255,255,.2)}.uk-card-primary.uk-card-body .uk-accordion-title::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-accordion-title::before,.uk-card-secondary.uk-card-body .uk-accordion-title::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-accordion-title::before,.uk-light .uk-accordion-title::before,.uk-offcanvas-bar .uk-accordion-title::before,.uk-overlay-primary .uk-accordion-title::before,.uk-section-primary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-section-secondary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-tile-primary:not(.uk-preserve-color) .uk-accordion-title::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-card-primary.uk-card-body .uk-open>.uk-accordion-title::before,.uk-card-primary>:not([class*=uk-card-media]) .uk-open>.uk-accordion-title::before,.uk-card-secondary.uk-card-body .uk-open>.uk-accordion-title::before,.uk-card-secondary>:not([class*=uk-card-media]) .uk-open>.uk-accordion-title::before,.uk-light .uk-open>.uk-accordion-title::before,.uk-offcanvas-bar .uk-open>.uk-accordion-title::before,.uk-overlay-primary .uk-open>.uk-accordion-title::before,.uk-section-primary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-section-secondary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-tile-primary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before,.uk-tile-secondary:not(.uk-preserve-color) .uk-open>.uk-accordion-title::before{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22rgba%28255,%20255,%20255,%200.7%29%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E")}*{--uk-inverse:initial}.uk-card-primary.uk-card-body,.uk-card-primary>:not([class*=uk-card-media]),.uk-card-secondary.uk-card-body,.uk-card-secondary>:not([class*=uk-card-media]),.uk-light,.uk-offcanvas-bar,.uk-overlay-primary,.uk-section-primary:not(.uk-preserve-color),.uk-section-secondary:not(.uk-preserve-color),.uk-tile-primary:not(.uk-preserve-color),.uk-tile-secondary:not(.uk-preserve-color){--uk-inverse:light}.uk-card-default.uk-card-body,.uk-card-default>:not([class*=uk-card-media]),.uk-dark,.uk-dropbar,.uk-dropdown,.uk-navbar-container:not(.uk-navbar-transparent),.uk-navbar-dropdown,.uk-overlay-default,.uk-section-default:not(.uk-preserve-color),.uk-section-muted:not(.uk-preserve-color),.uk-tile-default:not(.uk-preserve-color),.uk-tile-muted:not(.uk-preserve-color){--uk-inverse:dark}.uk-inverse-light{--uk-inverse:light!important}.uk-inverse-dark{--uk-inverse:dark!important}@media print{*,::after,::before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}} \ No newline at end of file diff --git a/web/static/uikit/js/uikit-icons.min.js b/web/static/uikit/js/uikit-icons.min.js new file mode 100644 index 0000000000000000000000000000000000000000..6493feb4964d8c6772a4eb6964e59895a5649098 --- /dev/null +++ b/web/static/uikit/js/uikit-icons.min.js @@ -0,0 +1 @@ +/*! UIkit 3.23.12 | https://www.getuikit.com | (c) 2014 - 2025 YOOtheme | MIT License */(function(e,i){typeof exports=="object"&&typeof module<"u"?module.exports=i():typeof define=="function"&&define.amd?define("uikiticons",i):(e=typeof globalThis<"u"?globalThis:e||self,e.UIkitIcons=i())})(this,function(){"use strict";function e(i){e.installed||i.icon.add({youtube:'',yootheme:'',yelp:'',xing:'',x:'',world:'',wordpress:'',whatsapp:'',warning:'',vimeo:'',"video-camera":'',users:'',user:'',upload:'',unlock:'',uikit:'',twitter:'',twitch:'',tv:'',tumblr:'',tripadvisor:'',"triangle-up":'',"triangle-right":'',"triangle-left":'',"triangle-down":'',trash:'',tiktok:'',thumbnails:'',threads:'',telegram:'',tag:'',tablet:'',"tablet-landscape":'',table:'',strikethrough:'',star:'',soundcloud:'',sorting:'',social:'',signal:'',"sign-out":'',"sign-in":'',shrink:'',settings:'',server:'',search:'',rss:'',reply:'',refresh:'',reddit:'',receiver:'',"quote-right":'',question:'',push:'',pull:'',print:'',plus:'',"plus-circle":'',play:'',"play-circle":'',pinterest:'',phone:'',"phone-landscape":'',pencil:'',"paint-bucket":'',nut:'',move:'',more:'',"more-vertical":'',minus:'',"minus-circle":'',microsoft:'',microphone:'',menu:'',mastodon:'',mail:'',lock:'',location:'',list:'',linkedin:'',link:'',"link-external":'',lifesaver:'',laptop:'',joomla:'',italic:'',instagram:'',info:'',image:'',home:'',history:'',heart:'',hashtag:'',happy:'',grid:'',google:'',gitter:'',github:'',"github-alt":'',"git-fork":'',"git-branch":'',future:'',foursquare:'',forward:'',folder:'',flickr:'',file:'',"file-text":'',"file-pdf":'',"file-edit":'',facebook:'',eye:'',"eye-slash":'',expand:'',etsy:'',dribbble:'',download:'',discord:'',desktop:'',database:'',crosshairs:'',"credit-card":'',copy:'',comments:'',commenting:'',comment:'',cog:'',code:'',"cloud-upload":'',"cloud-download":'',close:'',"close-circle":'',clock:'',"chevron-up":'',"chevron-right":'',"chevron-left":'',"chevron-down":'',"chevron-double-right":'',"chevron-double-left":'',check:'',cart:'',camera:'',calendar:'',bookmark:'',bolt:'',bold:'',bluesky:'',bell:'',behance:'',ban:'',bag:'',"arrow-up":'',"arrow-up-right":'',"arrow-right":'',"arrow-left":'',"arrow-down":'',"arrow-down-arrow-up":'',apple:'',android:'',"android-robot":'',album:'',"500px":''})}return typeof window<"u"&&window.UIkit&&window.UIkit.use(e),e}); diff --git a/web/static/uikit/js/uikit.min.js b/web/static/uikit/js/uikit.min.js new file mode 100644 index 0000000000000000000000000000000000000000..dc0d18928e3dff72b824aabfe3bdab47ce8aa2b3 --- /dev/null +++ b/web/static/uikit/js/uikit.min.js @@ -0,0 +1 @@ +/*! UIkit 3.23.12 | https://www.getuikit.com | (c) 2014 - 2025 YOOtheme | MIT License */(function(Se,Ie){typeof exports=="object"&&typeof module<"u"?module.exports=Ie():typeof define=="function"&&define.amd?define("uikit",Ie):(Se=typeof globalThis<"u"?globalThis:Se||self,Se.UIkit=Ie())})(this,function(){"use strict";const{hasOwnProperty:Se,toString:Ie}=Object.prototype;function gt(t,e){return Se.call(t,e)}const lr=/\B([A-Z])/g,Ft=ct(t=>t.replace(lr,"-$1").toLowerCase()),hr=/-(\w)/g,Ee=ct(t=>(t.charAt(0).toLowerCase()+t.slice(1)).replace(hr,(e,i)=>i.toUpperCase())),Ht=ct(t=>t.charAt(0).toUpperCase()+t.slice(1));function wt(t,e){var i;return(i=t==null?void 0:t.startsWith)==null?void 0:i.call(t,e)}function oe(t,e){var i;return(i=t==null?void 0:t.endsWith)==null?void 0:i.call(t,e)}function v(t,e){var i;return(i=t==null?void 0:t.includes)==null?void 0:i.call(t,e)}function xt(t,e){var i;return(i=t==null?void 0:t.findIndex)==null?void 0:i.call(t,e)}const{isArray:J,from:re}=Array,{assign:ft}=Object;function ot(t){return typeof t=="function"}function Ct(t){return t!==null&&typeof t=="object"}function Te(t){return Ie.call(t)==="[object Object]"}function si(t){return Ct(t)&&t===t.window}function Ce(t){return Wi(t)===9}function Pe(t){return Wi(t)>=1}function ae(t){return Wi(t)===1}function Wi(t){return!si(t)&&Ct(t)&&t.nodeType}function le(t){return typeof t=="boolean"}function H(t){return typeof t=="string"}function _e(t){return typeof t=="number"}function mt(t){return _e(t)||H(t)&&!isNaN(t-parseFloat(t))}function ni(t){return!(J(t)?t.length:Ct(t)&&Object.keys(t).length)}function X(t){return t===void 0}function ji(t){return le(t)?t:t==="true"||t==="1"||t===""?!0:t==="false"||t==="0"?!1:t}function $t(t){const e=Number(t);return isNaN(e)?!1:e}function S(t){return parseFloat(t)||0}function R(t){return t&&E(t)[0]}function E(t){return Pe(t)?[t]:Array.from(t||[]).filter(Pe)}function Lt(t){if(si(t))return t;t=R(t);const e=Ce(t)?t:t==null?void 0:t.ownerDocument;return(e==null?void 0:e.defaultView)||window}function Ae(t,e){return t===e||Ct(t)&&Ct(e)&&Object.keys(t).length===Object.keys(e).length&&he(t,(i,s)=>i===e[s])}function Ri(t,e,i){return t.replace(new RegExp(`${e}|${i}`,"g"),s=>s===e?i:e)}function Wt(t){return t[t.length-1]}function he(t,e){for(const i in t)if(e(t[i],i)===!1)return!1;return!0}function Vs(t,e){return t.slice().sort(({[e]:i=0},{[e]:s=0})=>i>s?1:s>i?-1:0)}function jt(t,e){return t.reduce((i,s)=>i+S(ot(e)?e(s):s[e]),0)}function Ys(t,e){const i=new Set;return t.filter(({[e]:s})=>i.has(s)?!1:i.add(s))}function oi(t,e){return e.reduce((i,s)=>({...i,[s]:t[s]}),{})}function K(t,e=0,i=1){return Math.min(Math.max($t(t)||0,e),i)}function A(){}function ri(...t){return[["bottom","top"],["right","left"]].every(([e,i])=>Math.min(...t.map(({[e]:s})=>s))-Math.max(...t.map(({[i]:s})=>s))>0)}function ai(t,e){return t.x<=e.right&&t.x>=e.left&&t.y<=e.bottom&&t.y>=e.top}function qi(t,e,i){const s=e==="width"?"height":"width";return{[s]:t[e]?Math.round(i*t[s]/t[e]):t[s],[e]:i}}function Gs(t,e){t={...t};for(const i in t)t=t[i]>e[i]?qi(t,i,e[i]):t;return t}function cr(t,e){t=Gs(t,e);for(const i in t)t=t[i]e[i]||(e[i]=t(i,...s))}function I(t,...e){for(const i of E(t)){const s=Rt(e).filter(n=>!$(i,n));s.length&&i.classList.add(...s)}}function _(t,...e){for(const i of E(t)){const s=Rt(e).filter(n=>$(i,n));s.length&&i.classList.remove(...s)}}function li(t,e,i){i=Rt(i),e=Rt(e).filter(s=>!v(i,s)),_(t,e),I(t,i)}function $(t,e){return[e]=Rt(e),E(t).some(i=>i.classList.contains(e))}function L(t,e,i){const s=Rt(e);X(i)||(i=!!i);for(const n of E(t))for(const o of s)n.classList.toggle(o,i)}function Rt(t){return t?J(t)?t.map(Rt).flat():String(t).split(" ").filter(Boolean):[]}function k(t,e,i){var s;if(Ct(e)){for(const n in e)k(t,n,e[n]);return}if(X(i))return(s=R(t))==null?void 0:s.getAttribute(e);for(const n of E(t))ot(i)&&(i=i.call(n,k(n,e))),i===null?Oe(n,e):n.setAttribute(e,i)}function Pt(t,e){return E(t).some(i=>i.hasAttribute(e))}function Oe(t,e){E(t).forEach(i=>i.removeAttribute(e))}function Z(t,e){for(const i of[e,`data-${e}`])if(Pt(t,i))return k(t,i)}const qt=typeof window<"u",U=qt&&document.dir==="rtl",ce=qt&&"ontouchstart"in window,ue=qt&&window.PointerEvent,ut=ue?"pointerdown":ce?"touchstart":"mousedown",Me=ue?"pointermove":ce?"touchmove":"mousemove",_t=ue?"pointerup":ce?"touchend":"mouseup",At=ue?"pointerenter":ce?"":"mouseenter",Ut=ue?"pointerleave":ce?"":"mouseleave",hi=ue?"pointercancel":"touchcancel",ur={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0};function Vi(t){return E(t).some(e=>ur[e.tagName.toLowerCase()])}const dr=qt&&Element.prototype.checkVisibility||function(){return this.offsetWidth||this.offsetHeight||this.getClientRects().length};function q(t){return E(t).some(e=>dr.call(e))}const De="input,select,textarea,button";function ci(t){return E(t).some(e=>C(e,De))}const de=`${De},a[href],[tabindex]`;function Be(t){return C(t,de)}function O(t){var e;return(e=R(t))==null?void 0:e.parentElement}function Ne(t,e){return E(t).filter(i=>C(i,e))}function C(t,e){return E(t).some(i=>i.matches(e))}function fe(t,e){const i=[];for(;t=O(t);)(!e||C(t,e))&&i.push(t);return i}function N(t,e){t=R(t);const i=t?re(t.children):[];return e?Ne(i,e):i}function yt(t,e){return e?E(t).indexOf(R(e)):N(O(t)).indexOf(t)}function Vt(t){return t=R(t),t&&["origin","pathname","search"].every(e=>t[e]===location[e])}function ui(t){if(Vt(t)){const{hash:e,ownerDocument:i}=R(t),s=decodeURIComponent(e).slice(1);return s?i.getElementById(s)||i.getElementsByName(s)[0]:i.documentElement}}function et(t,e){return Yi(t,Xs(t,e))}function ze(t,e){return Fe(t,Xs(t,e))}function Yi(t,e){return R(Zs(t,R(e),"querySelector"))}function Fe(t,e){return E(Zs(t,R(e),"querySelectorAll"))}function Xs(t,e=document){return Ce(e)||Js(t).isContextSelector?e:e.ownerDocument}const fr=/([!>+~-])(?=\s+[!>+~-]|\s*$)/g,pr=/(\([^)]*\)|[^,])+/g,Js=ct(t=>{let e=!1;if(!t||!H(t))return{};const i=[];for(let s of t.match(pr))s=s.trim().replace(fr,"$1 *"),e||(e=["!","+","~","-",">"].includes(s[0])),i.push(s);return{selector:i.join(","),selectors:i,isContextSelector:e}}),gr=/(\([^)]*\)|\S)*/,Ks=ct(t=>{t=t.slice(1).trim();const[e]=t.match(gr);return[e,t.slice(e.length+1)]});function Zs(t,e=document,i){var s;const n=Js(t);if(!n.isContextSelector)return n.selector?Gi(e,i,n.selector):t;t="";const o=n.selectors.length===1;for(let r of n.selectors){let a,l=e;if(r[0]==="!"&&([a,r]=Ks(r),l=(s=e.parentElement)==null?void 0:s.closest(a),!r&&o)||l&&r[0]==="-"&&([a,r]=Ks(r),l=l.previousElementSibling,l=C(l,a)?l:null,!r&&o))return l;if(l){if(o)return r[0]==="~"||r[0]==="+"?(r=`:scope > :nth-child(${yt(l)+1}) ${r}`,l=l.parentElement):r[0]===">"&&(r=`:scope ${r}`),Gi(l,i,r);t+=`${t?",":""}${mr(l)} ${r}`}}return Ce(e)||(e=e.ownerDocument),Gi(e,i,t)}function Gi(t,e,i){try{return t[e](i)}catch{return null}}function mr(t){const e=[];for(;t.parentNode;){const i=k(t,"id");if(i){e.unshift(`#${Xi(i)}`);break}else{let{tagName:s}=t;s!=="HTML"&&(s+=`:nth-child(${yt(t)+1})`),e.unshift(s),t=t.parentNode}}return e.join(" > ")}function Xi(t){return H(t)?CSS.escape(t):""}function w(...t){let[e,i,s,n,o=!1]=Ji(t);n.length>1&&(n=br(n)),o!=null&&o.self&&(n=wr(n)),s&&(n=vr(s,n));for(const r of i)for(const a of e)a.addEventListener(r,n,o);return()=>Yt(e,i,n,o)}function Yt(...t){let[e,i,,s,n=!1]=Ji(t);for(const o of i)for(const r of e)r.removeEventListener(o,s,n)}function z(...t){const[e,i,s,n,o=!1,r]=Ji(t),a=w(e,i,s,l=>{const c=!r||r(l);c&&(a(),n(l,c))},o);return a}function m(t,e,i){return Ki(t).every(s=>s.dispatchEvent(pe(e,!0,!0,i)))}function pe(t,e=!0,i=!1,s){return H(t)&&(t=new CustomEvent(t,{bubbles:e,cancelable:i,detail:s})),t}function Ji(t){return t[0]=Ki(t[0]),H(t[1])&&(t[1]=t[1].split(" ")),ot(t[2])&&t.splice(2,0,!1),t}function vr(t,e){return i=>{const s=t[0]===">"?Fe(t,i.currentTarget).reverse().find(n=>n.contains(i.target)):i.target.closest(t);s&&(i.current=s,e.call(this,i),delete i.current)}}function br(t){return e=>J(e.detail)?t(e,...e.detail):t(e)}function wr(t){return function(e){if(e.target===e.currentTarget||e.target===e.current)return t.call(null,e)}}function Qs(t){return t&&"addEventListener"in t}function xr(t){return Qs(t)?t:R(t)}function Ki(t){return J(t)?t.map(xr).filter(Boolean):H(t)?Fe(t):Qs(t)?[t]:E(t)}function pt(t){return t.pointerType==="touch"||!!t.touches}function kt(t){var e,i;const{clientX:s,clientY:n}=((e=t.touches)==null?void 0:e[0])||((i=t.changedTouches)==null?void 0:i[0])||t;return{x:s,y:n}}const $r={"animation-iteration-count":!0,"column-count":!0,"fill-opacity":!0,"flex-grow":!0,"flex-shrink":!0,"font-weight":!0,"line-height":!0,opacity:!0,order:!0,orphans:!0,"stroke-dasharray":!0,"stroke-dashoffset":!0,widows:!0,"z-index":!0,zoom:!0};function h(t,e,i,s){const n=E(t);for(const o of n)if(H(e)){if(e=di(e),X(i))return getComputedStyle(o).getPropertyValue(e);o.style.setProperty(e,mt(i)&&!$r[e]&&!tn(e)?`${i}px`:i||_e(i)?i:"",s)}else if(J(e)){const r={};for(const a of e)r[a]=h(o,a);return r}else if(Ct(e))for(const r in e)h(o,r,e[r],i);return n[0]}function St(t,e){for(const i in e)h(t,i,"")}const di=ct(t=>{if(tn(t))return t;t=Ft(t);const{style:e}=document.documentElement;if(t in e)return t;for(const i of["webkit","moz"]){const s=`-${i}-${t}`;if(s in e)return s}});function tn(t){return wt(t,"--")}const Zi="uk-transition",Qi="transitionend",ts="transitioncanceled";function yr(t,e,i=400,s="linear"){return i=Math.round(i),Promise.all(E(t).map(n=>new Promise((o,r)=>{for(const c in e)h(n,c);const a=setTimeout(()=>m(n,Qi),i);z(n,[Qi,ts],({type:c})=>{clearTimeout(a),_(n,Zi),St(n,l),c===ts?r():o(n)},{self:!0}),I(n,Zi);const l={transitionProperty:Object.keys(e).map(di).join(","),transitionDuration:`${i}ms`,transitionTimingFunction:s};h(n,{...l,...e})})))}const M={start:yr,async stop(t){m(t,Qi),await Promise.resolve()},async cancel(t){m(t,ts),await Promise.resolve()},inProgress(t){return $(t,Zi)}},He="uk-animation",en="animationend",fi="animationcanceled";function sn(t,e,i=200,s,n){return Promise.all(E(t).map(o=>new Promise((r,a)=>{$(o,He)&&m(o,fi);const l=[e,He,`${He}-${n?"leave":"enter"}`,s&&`uk-transform-origin-${s}`,n&&`${He}-reverse`],c=setTimeout(()=>m(o,en),i);z(o,[en,fi],({type:u})=>{clearTimeout(c),u===fi?a():r(o),h(o,"animationDuration",""),_(o,l)},{self:!0}),h(o,"animationDuration",`${i}ms`),I(o,l)})))}const Ot={in:sn,out(t,e,i,s){return sn(t,e,i,s,!0)},inProgress(t){return $(t,He)},cancel(t){m(t,fi)}};function kr(t){if(document.readyState!=="loading"){t();return}z(document,"DOMContentLoaded",t)}function F(t,...e){return e.some(i=>{var s;return((s=t==null?void 0:t.tagName)==null?void 0:s.toLowerCase())===i.toLowerCase()})}function nn(t){return t=x(t),t&&(t.innerHTML=""),t}function vt(t,e){return X(e)?x(t).innerHTML:W(nn(t),e)}const Sr=mi("prepend"),W=mi("append"),pi=mi("before"),gi=mi("after");function mi(t){return function(e,i){var s;const n=E(H(i)?It(i):i);return(s=x(e))==null||s[t](...n),on(n)}}function Q(t){E(t).forEach(e=>e.remove())}function Le(t,e){for(e=R(pi(t,e));e.firstElementChild;)e=e.firstElementChild;return W(e,t),e}function es(t,e){return E(E(t).map(i=>i.hasChildNodes()?Le(re(i.childNodes),e):W(i,e)))}function We(t){E(t).map(O).filter((e,i,s)=>s.indexOf(e)===i).forEach(e=>e.replaceWith(...e.childNodes))}const Ir=/^<(\w+)\s*\/?>(?:<\/\1>)?$/;function It(t){const e=Ir.exec(t);if(e)return document.createElement(e[1]);const i=document.createElement("template");return i.innerHTML=t.trim(),on(i.content.childNodes)}function on(t){return t.length>1?t:t[0]}function Mt(t,e){if(ae(t))for(e(t),t=t.firstElementChild;t;)Mt(t,e),t=t.nextElementSibling}function x(t,e){return rn(t)?R(It(t)):Yi(t,e)}function D(t,e){return rn(t)?E(It(t)):Fe(t,e)}function rn(t){return H(t)&&wt(t.trim(),"<")}const Gt={width:["left","right"],height:["top","bottom"]};function g(t){const e=ae(t)?R(t).getBoundingClientRect():{height:tt(t),width:vi(t),top:0,left:0};return{height:e.height,width:e.width,top:e.top,left:e.left,bottom:e.top+e.height,right:e.left+e.width}}function T(t,e){e&&h(t,{left:0,top:0});const i=g(t);if(t){const{scrollY:s,scrollX:n}=Lt(t),o={height:s,width:n};for(const r in Gt)for(const a of Gt[r])i[a]+=o[r]}if(!e)return i;for(const s of["left","top"])h(t,s,e[s]-i[s])}function is(t){let{top:e,left:i}=T(t);const{ownerDocument:{body:s,documentElement:n},offsetParent:o}=R(t);let r=o||n;for(;r&&(r===s||r===n)&&h(r,"position")==="static";)r=r.parentNode;if(ae(r)){const a=T(r);e-=a.top+S(h(r,"borderTopWidth")),i-=a.left+S(h(r,"borderLeftWidth"))}return{top:e-S(h(t,"marginTop")),left:i-S(h(t,"marginLeft"))}}function je(t){t=R(t);const e=[t.offsetTop,t.offsetLeft];for(;t=t.offsetParent;)if(e[0]+=t.offsetTop+S(h(t,"borderTopWidth")),e[1]+=t.offsetLeft+S(h(t,"borderLeftWidth")),h(t,"position")==="fixed"){const i=Lt(t);return e[0]+=i.scrollY,e[1]+=i.scrollX,e}return e}const tt=an("height"),vi=an("width");function an(t){const e=Ht(t);return(i,s)=>{if(X(s)){if(si(i))return i[`inner${e}`];if(Ce(i)){const n=i.documentElement;return Math.max(n[`offset${e}`],n[`scroll${e}`])}return i=R(i),s=h(i,t),s=s==="auto"?i[`offset${e}`]:S(s)||0,s-ge(i,t)}else return h(i,t,!s&&s!==0?"":+s+ge(i,t)+"px")}}function ge(t,e,i="border-box"){return h(t,"boxSizing")===i?jt(Gt[e],s=>S(h(t,`padding-${s}`))+S(h(t,`border-${s}-width`))):0}function bi(t){for(const e in Gt)for(const i in Gt[e])if(Gt[e][i]===t)return Gt[e][1-i];return t}function G(t,e="width",i=window,s=!1){return H(t)?jt(Tr(t),n=>{const o=Pr(n);return o?_r(o==="vh"?Ar():o==="vw"?vi(Lt(i)):s?i[`offset${Ht(e)}`]:g(i)[e],n):n}):S(t)}const Er=/-?\d+(?:\.\d+)?(?:v[wh]|%|px)?/g,Tr=ct(t=>t.toString().replace(/\s/g,"").match(Er)||[]),Cr=/(?:v[hw]|%)$/,Pr=ct(t=>(t.match(Cr)||[])[0]);function _r(t,e){return t*S(e)/100}let Re,me;function Ar(){return Re||(me||(me=x("
"),h(me,{height:"100vh",position:"fixed"}),w(window,"resize",()=>Re=null)),W(document.body,me),Re=me.clientHeight,Q(me),Re)}const Dt={read:Or,write:Mr,clear:Dr,flush:ln},wi=[],xi=[];function Or(t){return wi.push(t),ns(),t}function Mr(t){return xi.push(t),ns(),t}function Dr(t){cn(wi,t),cn(xi,t)}let ss=!1;function ln(){hn(wi),hn(xi.splice(0)),ss=!1,(wi.length||xi.length)&&ns()}function ns(){ss||(ss=!0,queueMicrotask(ln))}function hn(t){let e;for(;e=t.shift();)try{e()}catch(i){console.error(i)}}function cn(t,e){const i=t.indexOf(e);return~i&&t.splice(i,1)}class un{init(){this.positions=[];let e;this.unbind=w(document,"mousemove",i=>e=kt(i)),this.interval=setInterval(()=>{e&&(this.positions.push(e),this.positions.length>5&&this.positions.shift())},50)}cancel(){var e;(e=this.unbind)==null||e.call(this),clearInterval(this.interval)}movesTo(e){if(!this.positions||this.positions.length<2)return!1;const i=g(e),{left:s,right:n,top:o,bottom:r}=i,[a]=this.positions,l=Wt(this.positions),c=[a,l];return ai(l,i)?!1:[[{x:s,y:o},{x:n,y:r}],[{x:s,y:r},{x:n,y:o}]].some(d=>{const f=Br(c,d);return f&&ai(f,i)})}}function Br([{x:t,y:e},{x:i,y:s}],[{x:n,y:o},{x:r,y:a}]){const l=(a-o)*(i-t)-(r-n)*(s-e);if(l===0)return!1;const c=((r-n)*(e-o)-(a-o)*(t-n))/l;return c<0?!1:{x:t+c*(i-t),y:e+c*(s-e)}}function dn(t,e,i={},{intersecting:s=!0}={}){const n=new IntersectionObserver(s?(o,r)=>{o.some(a=>a.isIntersecting)&&e(o,r)}:e,i);for(const o of E(t))n.observe(o);return n}const Nr=qt&&window.ResizeObserver;function qe(t,e,i={box:"border-box"}){if(Nr)return fn(ResizeObserver,t,e,i);const s=[w(window,"load resize",e),w(document,"loadedmetadata load",e,!0)];return{disconnect:()=>s.map(n=>n())}}function os(t){return{disconnect:w([window,window.visualViewport],"resize",t)}}function rs(t,e,i){return fn(MutationObserver,t,e,i)}function fn(t,e,i,s){const n=new t(i);for(const o of E(e))n.observe(o,s);return n}function as(t){hs(t)&&cs(t,{func:"playVideo",method:"play"}),ls(t)&&t.play().catch(A)}function $i(t){hs(t)&&cs(t,{func:"pauseVideo",method:"pause"}),ls(t)&&t.pause()}function pn(t){hs(t)&&cs(t,{func:"mute",method:"setVolume",value:0}),ls(t)&&(t.muted=!0)}function ls(t){return F(t,"video")}function hs(t){return F(t,"iframe")&&(gn(t)||mn(t))}function gn(t){return!!t.src.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/(watch\?v=[^&\s]+|embed)|youtu\.be\/.*/)}function mn(t){return!!t.src.match(/vimeo\.com\/video\/.*/)}async function cs(t,e){await Fr(t),vn(t,e)}function vn(t,e){t.contentWindow.postMessage(JSON.stringify({event:"command",...e}),"*")}const us="_ukPlayer";let zr=0;function Fr(t){if(t[us])return t[us];const e=gn(t),i=mn(t),s=++zr;let n;return t[us]=new Promise(o=>{e&&z(t,"load",()=>{const r=()=>vn(t,{event:"listening",id:s});n=setInterval(r,100),r()}),z(window,"message",o,!1,({data:r})=>{try{return r=JSON.parse(r),e&&(r==null?void 0:r.id)===s&&r.event==="onReady"||i&&Number(r==null?void 0:r.player_id)===s}catch{}}),t.src=`${t.src}${v(t.src,"?")?"&":"?"}${e?"enablejsapi=1":`api=1&player_id=${s}`}`}).then(()=>clearInterval(n))}function Hr(t,e=0,i=0){return q(t)?ri(...Jt(t).map(s=>{const{top:n,left:o,bottom:r,right:a}=at(s);return{top:n-e,left:o-i,bottom:r+e,right:a+i}}).concat(T(t))):!1}function bn(t,{offset:e=0}={}){const i=q(t)?Xt(t,!1,["hidden"]):[];return i.reduce((r,a,l)=>{const{scrollTop:c,scrollHeight:u,offsetHeight:d}=a,f=at(a),p=u-f.height,{height:b,top:y}=i[l-1]?at(i[l-1]):T(t);let P=Math.ceil(y-f.top-e+c);return e>0&&dp?(e-=P-p,P=p):P<0&&(e-=P,P=0),()=>s(a,P-c,t,p).then(r)},()=>Promise.resolve())();function s(r,a,l,c){return new Promise(u=>{const d=r.scrollTop,f=n(Math.abs(a)),p=Date.now(),b=ps(r)===r,y=T(l).top+(b?0:d);let P=0,it=15;(function Tt(){const zt=o(K((Date.now()-p)/f));let bt=0;i[0]===r&&d+ah(r,"position")==="fixed");return~o&&(n=n.slice(o)),[s].concat(n.filter(r=>h(r,"overflow").split(" ").some(a=>v(["auto","scroll",...i],a))&&(!e||r.scrollHeight>at(r).height))).reverse()}function Bt(...t){return Xt(...t)[0]}function Jt(t){return Xt(t,!1,["hidden","clip"])}function at(t){const e=Lt(t),i=ps(t),s=!Pe(t)||t.contains(i);if(s&&e.visualViewport){let{height:l,width:c,scale:u,pageTop:d,pageLeft:f}=e.visualViewport;return l=Math.round(l*u),c=Math.round(c*u),{height:l,width:c,top:d,left:f,bottom:d+l,right:f+c}}let n=T(s?e:t);if(h(t,"display")==="inline")return n;const{body:o,documentElement:r}=e.document,a=s?i===r||i.clientHeight!a.contains(r)&&!fs(a,"static")))=f[u])continue;p=jr(t,e,i,l)[u]-s[u];const y=Wr(t,e[l],o,l);if(!ki(gs(s,p,l),y,l)){if(ki(s,y,l))continue;if(i.recursion)return!1;const P=Rr(t,e,i);if(P&&ki(P,y,1-l))return P;continue}}else if(r[l]==="shift"){const b=T(e[l]),{offset:y}=i;p=K(K(s[u],f[u],f[d]-s[c]),b[u]-s[c]+y[l],b[d]-y[l])-s[u]}a=gs(a,p,l)}return a}function yn(t,e,i){let{attach:s,offset:n}={attach:{element:["left","top"],target:["left","top"],...i.attach},offset:[0,0],...i},o=T(t);for(const[r,[a,,l,c]]of Object.entries(lt)){const u=s.target[r]===s.element[r]?at(e[r]):T(e[r]);o=gs(o,u[l]-o[l]+kn(s.target[r],c,u[a])-kn(s.element[r],c,o[a])+ +n[r],r)}return o}function gs(t,e,i){const[,s,n,o]=lt[i],r={...t};return r[n]=t[s]=t[n]+e,r[o]+=e,r}function kn(t,e,i){return t==="center"?i/2:t===e?i:0}function Lr(t,e,i,s,n){let o=In(...Sn(t,e).map(at));return i&&(o[lt[n][2]]+=i,o[lt[n][3]]-=i),s&&(o=In(o,T(J(s)?s[n]:s))),o}function Wr(t,e,i,s){const[n,o,r,a]=lt[s],[l]=Sn(t,e),c=at(l);return["auto","scroll"].includes(h(l,`overflow-${o}`))&&(c[r]-=l[`scroll${Ht(r)}`],c[a]=c[r]+l[`scroll${Ht(n)}`]),c[r]+=i,c[a]-=i,c}function Sn(t,e){return Jt(e).filter(i=>i.contains(t))}function In(...t){let e={};for(const i of t)for(const[,,s,n]of lt)e[s]=Math.max(e[s]||0,i[s]),e[n]=Math.min(...[e[n],i[n]].filter(Boolean));return e}function ki(t,e,i){const[,,s,n]=lt[i];return t[s]>=e[s]&&t[n]<=e[n]}function jr(t,e,{offset:i,attach:s},n){return yn(t,e,{attach:{element:En(s.element,n),target:En(s.target,n)},offset:qr(i,n)})}function Rr(t,e,i){return $n(t,e,{...i,attach:{element:i.attach.element.map(Tn).reverse(),target:i.attach.target.map(Tn).reverse()},offset:i.offset.reverse(),placement:i.placement.reverse(),recursion:!0})}function En(t,e){const i=[...t],s=lt[e].indexOf(t[e]);return~s&&(i[e]=lt[e][1-s%2+2]),i}function Tn(t){for(let e=0;edocument,handler(){document.hidden?this.stop():this.start()}},methods:{start(){this.stop(),this.update()},stop(){this.timer&&(clearInterval(this.timer),m(this.$el,"countdownstop"),this.timer=null)},update(){const t=Gr(this.date);t.total?this.timer||(this.started=!0,this.timer=setInterval(this.update,1e3),m(this.$el,"countdownstart")):(this.stop(),this.end||(m(this.$el,"countdownend"),this.end=!0,this.reload&&this.started&&window.location.reload()));for(const e of Vr){const i=x(this.clsWrapper.replace("%unit%",e),this.$el);if(!i)continue;let s=Math.trunc(t[e]).toString().padStart(2,"0");i.textContent!==s&&(s=s.split(""),s.length!==i.children.length&&vt(i,s.map(()=>"").join("")),s.forEach((n,o)=>i.children[o].textContent=n))}}}};function Gr(t){const e=Math.max(0,t-Date.now())/1e3;return{total:e,seconds:e%60,minutes:e/60%60,hours:e/60/60%24,days:e/60/60/24}}const V={};V.events=V.watch=V.observe=V.created=V.beforeConnect=V.connected=V.beforeDisconnect=V.disconnected=V.destroy=ms,V.args=function(t,e){return e!==!1&&ms(e||t)},V.update=function(t,e){return Vs(ms(t,ot(e)?{read:e}:e),"order")},V.props=function(t,e){if(J(e)){const i={};for(const s of e)i[s]=String;e=i}return V.methods(t,e)},V.computed=V.methods=function(t,e){return e?t?{...t,...e}:e:t},V.i18n=V.data=function(t,e,i){return i?Cn(t,e,i):e?t?function(s){return Cn(t,e,s)}:e:t};function Cn(t,e,i){return V.computed(ot(t)?t.call(i,i):t,ot(e)?e.call(i,i):e)}function ms(t,e){return t=t&&!J(t)?[t]:t,e?t?t.concat(e):J(e)?e:[e]:t}function Xr(t,e){return X(e)?t:e}function Ue(t,e,i){const s={};if(ot(e)&&(e=e.options),e.extends&&(t=Ue(t,e.extends,i)),e.mixins)for(const o of e.mixins)t=Ue(t,o,i);for(const o in t)n(o);for(const o in e)gt(t,o)||n(o);function n(o){s[o]=(V[o]||Xr)(t[o],e[o],i)}return s}function ve(t,e=[]){try{return t?wt(t,"{")?JSON.parse(t):e.length&&!v(t,":")?{[e[0]]:t}:t.split(";").reduce((i,s)=>{const[n,o]=s.split(/:(.*)/);return n&&!X(o)&&(i[n.trim()]=o.trim()),i},{}):{}}catch{return{}}}function vs(t,e){return t===Boolean?ji(e):t===Number?$t(e):t==="list"?Kr(e):t===Object&&H(e)?ve(e):t?t(e):e}const Jr=/,(?![^(]*\))/;function Kr(t){return J(t)?t:H(t)?t.split(Jr).map(e=>mt(e)?$t(e):ji(e.trim())):[t]}function Zr(t){t._data={},t._updates=[...t.$options.update||[]],t._disconnect.push(()=>t._updates=t._data=null)}function Qr(t,e){t._updates.unshift(e)}function Ve(t,e="update"){t._connected&&t._updates.length&&(t._queued||(t._queued=new Set,Dt.read(()=>{t._connected&&ta(t,t._queued),t._queued=null})),t._queued.add(e.type||e))}function ta(t,e){for(const{read:i,write:s,events:n=[]}of t._updates){if(!e.has("update")&&!n.some(r=>e.has(r)))continue;let o;i&&(o=i.call(t,t._data,e),o&&Te(o)&&ft(t._data,o)),s&&o!==!1&&Dt.write(()=>{t._connected&&s.call(t,t._data,e)})}}function dt(t){return Ge(qe,t,"resize")}function be(t){return Ge(dn,t)}function Si(t){return Ge(rs,t)}function Ii(t={}){return be({handler:function(e,i){const{targets:s=this.$el,preload:n=5}=t;for(const o of E(ot(s)?s(this):s))D('[loading="lazy"]',o).slice(0,n-1).forEach(r=>Oe(r,"loading"));for(const o of e.filter(({isIntersecting:r})=>r).map(({target:r})=>r))i.unobserve(o)},...t})}function bs(t){return Ge((e,i)=>os(i),t,"resize")}function Ye(t){return Ge((e,i)=>({disconnect:w(ia(e),"scroll",i,{passive:!0})}),t,"scroll")}function Pn(t){return{observe(e,i){return{observe:A,unobserve:A,disconnect:w(e,ut,i,{passive:!0})}},handler(e){if(!pt(e))return;const i=kt(e),s="tagName"in e.target?e.target:O(e.target);z(document,`${_t} ${hi} scroll`,n=>{const{x:o,y:r}=kt(n);(n.type!=="scroll"&&s&&o&&Math.abs(i.x-o)>100||r&&Math.abs(i.y-r)>100)&&setTimeout(()=>{m(s,"swipe"),m(s,`swipe${ea(i.x,i.y,o,r)}`)})})},...t}}function Ge(t,e,i){return{observe:t,handler(){Ve(this,i)},...e}}function ea(t,e,i,s){return Math.abs(t-i)>=Math.abs(e-s)?t-i>0?"Left":"Right":e-s>0?"Up":"Down"}function ia(t){return E(t).map(e=>{const{ownerDocument:i}=e,s=Bt(e,!0);return s===i.scrollingElement?i:s})}var _n={props:{margin:String,firstColumn:Boolean},data:{margin:"uk-margin-small-top",firstColumn:"uk-first-column"},observe:[Si({options:{childList:!0}}),Si({options:{attributes:!0,attributeFilter:["style"]}}),dt({handler(t){for(const{borderBoxSize:[{inlineSize:e,blockSize:i}]}of t)if(e||i){this.$emit("resize");return}},target:({$el:t})=>[t,...N(t)]})],update:{read(){return{rows:ws(N(this.$el))}},write({rows:t}){for(const e of t)for(const i of e)L(i,this.margin,t[0]!==e),L(i,this.firstColumn,e[U?e.length-1:0]===i)},events:["resize"]}};function ws(t){const e=[[]],i=t.some((s,n)=>n&&t[n-1].offsetParent!==s.offsetParent);for(const s of t){if(!q(s))continue;const n=xs(s,i);for(let o=e.length-1;o>=0;o--){const r=e[o];if(!r[0]){r.push(s);break}const a=xs(r[0],i);if(n.top>=a.bottom-1&&n.top!==a.top){e.push([s]);break}if(n.bottom-1>a.top||n.top===a.top){let l=r.length-1;for(;l>=0;l--){const c=xs(r[l],i);if(n.left>=c.left)break}r.splice(l+1,0,s);break}if(o===0){e.unshift([s]);break}}}return e}function xs(t,e=!1){let{offsetTop:i,offsetLeft:s,offsetHeight:n,offsetWidth:o}=t;return e&&([i,s]=je(t)),{top:i,left:s,bottom:i+n,right:s+o}}const $s="uk-transition-leave",ys="uk-transition-enter";function An(t,e,i,s=0){const n=ks(e,!0),o={opacity:1},r={opacity:0},a=()=>n===ks(e),l=d=>()=>a()?d():Promise.reject(),c=l(async()=>{I(e,$s),await(s?Promise.all(Mn(e).map(async(d,f)=>(await Ss(f*s),M.start(d,r,i/2,"ease")))):M.start(e,r,i/2,"ease")),_(e,$s)}),u=l(async()=>{const d=tt(e);I(e,ys),t(),h(s?N(e):e,r),tt(e,d),await Ss(),tt(e,"");const f=tt(e);h(e,"alignContent","flex-start"),tt(e,d);let p=[],b=i/2;if(s){const y=Mn(e);h(N(e),r),p=y.map(async(P,it)=>{await Ss(it*s),await M.start(P,o,i/2,"ease"),a()&&St(P,o)}),b+=y.length*s}if(!s||d!==f){const y={height:f,...s?{}:o};p.push(M.start(e,y,b,"ease"))}await Promise.all(p),_(e,ys),a()&&(St(e,{height:"",alignContent:"",...o}),delete e.dataset.transition)});return $(e,$s)?On(e).then(u):$(e,ys)?On(e).then(c).then(u):c().then(u)}function ks(t,e){return e&&(t.dataset.transition=1+ks(t)),$t(t.dataset.transition)||0}function On(t){return Promise.all(N(t).filter(M.inProgress).map(e=>new Promise(i=>z(e,"transitionend transitioncanceled",i))))}function Mn(t){return ws(N(t)).flat().filter(q)}function Ss(t){return new Promise(e=>setTimeout(e,t))}async function sa(t,e,i){await Nn();let s=N(e);const n=s.map(p=>Dn(p,!0)),o={...h(e,["height","padding"]),display:"block"},r=s.concat(e);await Promise.all(r.map(M.cancel)),h(r,"transitionProperty","none"),await t(),s=s.concat(N(e).filter(p=>!v(s,p))),await Promise.resolve(),h(r,"transitionProperty","");const a=k(e,"style"),l=h(e,["height","padding"]),[c,u]=na(e,s,n),d=s.map(p=>({style:k(p,"style")}));s.forEach((p,b)=>u[b]&&h(p,u[b])),h(e,o),m(e,"scroll"),await Nn();const f=s.map((p,b)=>O(p)===e&&M.start(p,c[b],i,"ease")).concat(M.start(e,l,i,"ease"));try{await Promise.all(f),s.forEach((p,b)=>{k(p,d[b]),O(p)===e&&h(p,"display",c[b].opacity===0?"none":"")}),k(e,"style",a)}catch{k(s,"style",""),St(e,o)}}function Dn(t,e){const i=h(t,"zIndex");return q(t)?{display:"",opacity:e?h(t,"opacity"):"0",pointerEvents:"none",position:"absolute",zIndex:i==="auto"?yt(t):i,...Bn(t)}:!1}function na(t,e,i){const s=e.map((o,r)=>O(o)&&r in i?i[r]?q(o)?Bn(o):{opacity:0}:{opacity:q(o)?1:0}:!1),n=s.map((o,r)=>{const a=O(e[r])===t&&(i[r]||Dn(e[r]));if(!a)return!1;if(!o)delete a.opacity;else if(!("opacity"in o)){const{opacity:l}=a;l%1?o.opacity=1:delete a.opacity}return a});return[s,n]}function Bn(t){const{height:e,width:i}=g(t);return{height:e,width:i,transform:"",...is(t),...h(t,["marginTop","marginLeft"])}}function Nn(){return new Promise(t=>requestAnimationFrame(t))}var zn={props:{duration:Number,animation:Boolean},data:{duration:150,animation:"slide"},methods:{animate(t,e=this.$el){const i=this.animation;return(i==="fade"?An:i==="delayed-fade"?(...n)=>An(...n,40):i?sa:()=>(t(),Promise.resolve()))(t,e,this.duration).catch(A)}}};function Et(t){t.target.closest('a[href="#"],a[href=""]')&&t.preventDefault()}const B={TAB:9,ESC:27,SPACE:32,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40};var oa={mixins:[zn],args:"target",props:{target:String,selActive:Boolean},data:{target:"",selActive:!1,attrItem:"uk-filter-control",cls:"uk-active",duration:250},computed:{children:({target:t},e)=>D(`${t} > *`,e),toggles:({attrItem:t},e)=>D(`[${t}],[data-${t}]`,e)},watch:{toggles(t){this.updateState();const e=D(this.selActive,this.$el);for(const i of t){this.selActive!==!1&&L(i,this.cls,v(e,i));const s=ca(i);F(s,"a")&&(s.role="button")}},children(t,e){e&&this.updateState()}},events:{name:"click keydown",delegate:({attrItem:t})=>`[${t}],[data-${t}]`,handler(t){t.type==="keydown"&&t.keyCode!==B.SPACE||t.target.closest("a,button")&&(Et(t),this.apply(t.current))}},methods:{apply(t){const e=this.getState(),i=Hn(t,this.attrItem,this.getState());ra(e,i)||this.setState(i)},getState(){return this.toggles.filter(t=>$(t,this.cls)).reduce((t,e)=>Hn(e,this.attrItem,t),{filter:{"":""},sort:[]})},async setState(t,e=!0){t={filter:{"":""},sort:[],...t},m(this.$el,"beforeFilter",[this,t]);for(const i of this.toggles)L(i,this.cls,la(i,this.attrItem,t));await Promise.all(D(this.target,this.$el).map(i=>{const s=()=>aa(t,i,N(i));return e?this.animate(s,i):s()})),m(this.$el,"afterFilter",[this])},updateState(){Dt.write(()=>this.setState(this.getState(),!1))}}};function Fn(t,e){return ve(Z(t,e),["filter"])}function ra(t,e){return["filter","sort"].every(i=>Ae(t[i],e[i]))}function aa(t,e,i){for(const o of i)h(o,"display",Object.values(t.filter).every(r=>!r||C(o,r))?"":"none");const[s,n]=t.sort;if(s){const o=ha(i,s,n);Ae(o,i)||W(e,o)}}function Hn(t,e,i){const{filter:s,group:n,sort:o,order:r="asc"}=Fn(t,e);return(s||X(o))&&(n?s?(delete i.filter[""],i.filter[n]=s):(delete i.filter[n],(ni(i.filter)||""in i.filter)&&(i.filter={"":s||""})):i.filter={"":s||""}),X(o)||(i.sort=[o,r]),i}function la(t,e,{filter:i={"":""},sort:[s,n]}){const{filter:o="",group:r="",sort:a,order:l="asc"}=Fn(t,e);return X(a)?r in i&&o===i[r]||!o&&r&&!(r in i)&&!i[""]:s===a&&n===l}function ha(t,e,i){return[...t].sort((s,n)=>Z(s,e).localeCompare(Z(n,e),void 0,{numeric:!0})*(i==="asc"||-1))}function ca(t){return x("a,button",t)||t}var ua={args:"dataSrc",props:{dataSrc:String,sources:String,margin:String,target:String,loading:String},data:{dataSrc:"",sources:!1,margin:"50%",target:!1,loading:"lazy"},connected(){this.loading!=="lazy"?this.load():Es(this.$el)&&(this.$el.loading="lazy",Is(this.$el))},disconnected(){this.img&&(this.img.onload=""),delete this.img},observe:be({handler(t,e){this.load(),e.disconnect()},options:({margin:t})=>({rootMargin:t}),filter:({loading:t})=>t==="lazy",target:({$el:t,$props:e})=>e.target?[t,...ze(e.target,t)]:t}),methods:{load(){if(this.img)return this.img;const t=Es(this.$el)?this.$el:fa(this.$el,this.dataSrc,this.sources);return Oe(t,"loading"),Is(this.$el,t.currentSrc),this.img=t}}};function Is(t,e){if(Es(t)){const i=O(t);(F(i,"picture")?N(i):[t]).forEach(n=>Ln(n,n))}else e&&!v(t.style.backgroundImage,e)&&(h(t,"backgroundImage",`url(${Xi(e)})`),m(t,pe("load",!1)))}const da=["data-src","data-srcset","sizes"];function Ln(t,e){for(const i of da){const s=Z(t,i);s&&k(e,i.replace(/data-/g,""),s)}}function fa(t,e,i){const s=new Image;return Wn(s,i),Ln(t,s),s.onload=()=>Is(t,s.currentSrc),s.src=e,s}function Wn(t,e){if(e=pa(e),e.length){const i=It("");for(const s of e){const n=It("");k(n,s),W(i,n)}W(i,t)}}function pa(t){if(!t)return[];if(wt(t,"["))try{t=JSON.parse(t)}catch{t=[]}else t=ve(t);return J(t)||(t=[t]),t.filter(e=>!ni(e))}function Es(t){return F(t,"img")}let Ts;function jn(t){const e=w(t,"touchstart",n=>{if(n.targetTouches.length!==1||C(n.target,'input[type="range"'))return;let o=kt(n).y;const r=w(t,"touchmove",a=>{const l=kt(a).y;l!==o&&(o=l,Xt(a.target).some(c=>{if(!t.contains(c))return!1;let{scrollHeight:u,clientHeight:d}=c;return d{Ts=!1,e(),St(i,s)}}var Xe={props:{container:Boolean},data:{container:!0},computed:{container({container:t}){return t===!0&&this.$container||t&&x(t)}}},Rn={props:{pos:String,offset:Boolean,flip:Boolean,shift:Boolean,inset:Boolean},data:{pos:`bottom-${U?"right":"left"}`,offset:!1,flip:!0,shift:!0,inset:!1},connected(){this.pos=this.$props.pos.split("-").concat("center").slice(0,2),[this.dir,this.align]=this.pos,this.axis=v(["top","bottom"],this.dir)?"y":"x"},methods:{positionAt(t,e,i){let s=[this.getPositionOffset(t),this.getShiftOffset(t)];const n=[this.flip&&"flip",this.shift&&"shift"],o={element:[this.inset?this.dir:bi(this.dir),this.align],target:[this.dir,this.align]};if(this.axis==="y"){for(const l in o)o[l].reverse();s.reverse(),n.reverse()}const r=Cs(t),a=g(t);h(t,{top:-a.height,left:-a.width}),xn(t,e,{attach:o,offset:s,boundary:i,placement:n,viewportOffset:this.getViewportOffset(t)}),r()},getPositionOffset(t=this.$el){return G(this.offset===!1?h(t,"--uk-position-offset"):this.offset,this.axis==="x"?"width":"height",t)*(v(["left","top"],this.dir)?-1:1)*(this.inset?-1:1)},getShiftOffset(t=this.$el){return this.align==="center"?0:G(h(t,"--uk-position-shift-offset"),this.axis==="y"?"width":"height",t)*(v(["left","top"],this.align)?1:-1)},getViewportOffset(t){return G(h(t,"--uk-position-viewport-offset"))}}};function Cs(t){const e=Bt(t),{scrollTop:i}=e;return()=>{i!==e.scrollTop&&(e.scrollTop=i)}}var Kt={props:{cls:Boolean,animation:"list",duration:Number,velocity:Number,origin:String,transition:String},data:{cls:!1,animation:[!1],duration:200,velocity:.2,origin:!1,transition:"ease",clsEnter:"uk-togglable-enter",clsLeave:"uk-togglable-leave"},computed:{hasAnimation:({animation:t})=>!!t[0],hasTransition:({animation:t})=>["slide","reveal"].some(e=>wt(t[0],e))},methods:{async toggleElement(t,e,i){try{return await Promise.all(E(t).map(s=>{const n=le(e)?e:!this.isToggled(s);if(!m(s,`before${n?"show":"hide"}`,[this]))return Promise.reject();const o=(ot(i)?i:i===!1||!this.hasAnimation?ga:this.hasTransition?ma:va)(s,n,this),r=n?this.clsEnter:this.clsLeave;I(s,r),m(s,n?"show":"hide",[this]);const a=()=>{var l;if(_(s,r),m(s,n?"shown":"hidden",[this]),n){const c=Cs(s);(l=D("[autofocus]",s).find(q))==null||l.focus(),c()}};return o?o.then(a,()=>(_(s,r),Promise.reject())):a()})),!0}catch{return!1}},isToggled(t=this.$el){return t=R(t),$(t,this.clsEnter)?!0:$(t,this.clsLeave)?!1:this.cls?$(t,this.cls.split(" ")[0]):q(t)},_toggle(t,e){if(!t)return;e=!!e;let i;this.cls?(i=v(this.cls," ")||e!==$(t,this.cls),i&&L(t,this.cls,v(this.cls," ")?void 0:e)):(i=e===t.hidden,i&&(t.hidden=!e)),i&&m(t,"toggled",[e,this])}}};function ga(t,e,{_toggle:i}){return Ot.cancel(t),M.cancel(t),i(t,e)}async function ma(t,e,{animation:i,duration:s,velocity:n,transition:o,_toggle:r}){var a;const[l="reveal",c="top"]=((a=i[0])==null?void 0:a.split("-"))||[],u=[["left","right"],["top","bottom"]],d=u[v(u[0],c)?0:1],f=d[1]===c,b=["width","height"][u.indexOf(d)],y=`margin-${d[0]}`,P=`margin-${c}`;let it=g(t)[b];const Tt=M.inProgress(t);await M.cancel(t),e&&r(t,!0);const zt=Object.fromEntries(["padding","border","width","height","minWidth","minHeight","overflowY","overflowX",y,P].map(ar=>[ar,t.style[ar]])),bt=g(t),Us=S(h(t,y)),nr=S(h(t,P)),ne=bt[b]+nr;!Tt&&!e&&(it+=nr);const[Li]=es(t,"
");h(Li,{boxSizing:"border-box",height:bt.height,width:bt.width,...h(t,["overflow","padding","borderTop","borderRight","borderBottom","borderLeft","borderImage",P])}),h(t,{padding:0,border:0,minWidth:0,minHeight:0,[P]:0,width:bt.width,height:bt.height,overflow:"hidden",[b]:it});const or=it/ne;s=(n*ne+s)*(e?1-or:or);const rr={[b]:e?ne:0};f&&(h(t,y,ne-it+Us),rr[y]=e?Us:ne+Us),!f^l==="reveal"&&(h(Li,y,-ne+it),M.start(Li,{[y]:e?0:-ne},s,o));try{await M.start(t,rr,s,o)}finally{h(t,zt),We(Li.firstChild),e||r(t,!1)}}function va(t,e,i){const{animation:s,duration:n,_toggle:o}=i;return e?(o(t,!0),Ot.in(t,s[0],n,i.origin)):Ot.out(t,s[1]||s[0],n,i.origin).then(()=>o(t,!1))}const nt=[];var Ps={mixins:[st,Xe,Kt],props:{selPanel:String,selClose:String,escClose:Boolean,bgClose:Boolean,stack:Boolean,role:String},data:{cls:"uk-open",escClose:!0,bgClose:!0,overlay:!0,stack:!1,role:"dialog"},computed:{panel:({selPanel:t},e)=>x(t,e),transitionElement(){return this.panel}},connected(){const t=this.panel||this.$el;t.role=this.role,this.overlay&&(t.ariaModal=!0)},beforeDisconnect(){v(nt,this)&&this.toggleElement(this.$el,!1,!1)},events:[{name:"click",delegate:({selClose:t})=>`${t},a[href*="#"]`,handler(t){const{current:e,defaultPrevented:i}=t,{hash:s}=e;!i&&s&&Vt(e)&&!this.$el.contains(x(s))?this.hide():C(e,this.selClose)&&(Et(t),this.hide())}},{name:"toggle",self:!0,handler(t,e){t.defaultPrevented||(t.preventDefault(),this.target=e==null?void 0:e.$el,this.isToggled()===v(nt,this)&&this.toggle())}},{name:"beforeshow",self:!0,handler(t){if(v(nt,this))return!1;!this.stack&&nt.length?(Promise.all(nt.map(e=>e.hide())).then(this.show),t.preventDefault()):nt.push(this)}},{name:"show",self:!0,handler(){this.stack&&h(this.$el,"zIndex",S(h(this.$el,"zIndex"))+nt.length);const t=[this.overlay&&wa(this),this.overlay&&jn(this.$el),this.bgClose&&xa(this),this.escClose&&$a(this)];z(this.$el,"hidden",()=>t.forEach(e=>e&&e()),{self:!0}),I(document.documentElement,this.clsPage),Un(this.target,!0)}},{name:"shown",self:!0,handler(){Be(this.$el)||(this.$el.tabIndex=-1),C(this.$el,":focus-within")||this.$el.focus()}},{name:"hidden",self:!0,handler(){v(nt,this)&&nt.splice(nt.indexOf(this),1),h(this.$el,"zIndex","");const{target:t}=this;nt.some(e=>e.clsPage===this.clsPage)||(_(document.documentElement,this.clsPage),queueMicrotask(()=>Be(t)&&t.focus())),Un(t,!1),this.target=null}}],methods:{toggle(){return this.isToggled()?this.hide():this.show()},show(){return this.container&&O(this.$el)!==this.container?(W(this.container,this.$el),new Promise(t=>requestAnimationFrame(()=>this.show().then(t)))):this.toggleElement(this.$el,!0,qn)},hide(){return this.toggleElement(this.$el,!1,qn)}}};function qn(t,e,{transitionElement:i,_toggle:s}){return new Promise((n,o)=>z(t,"show hide",()=>{var r;(r=t._reject)==null||r.call(t),t._reject=o,s(t,e);const a=z(i,"transitionstart",()=>{z(i,"transitionend transitioncancel",n,{self:!0}),clearTimeout(l)},{self:!0}),l=setTimeout(()=>{a(),n()},ba(h(i,"transitionDuration")))})).then(()=>delete t._reject)}function ba(t){return t?oe(t,"ms")?S(t):S(t)*1e3:0}function wa(t){return w(document,"focusin",e=>{Wt(nt)===t&&!t.$el.contains(e.target)&&t.$el.focus()})}function xa(t){return w(document,ut,({target:e})=>{Wt(nt)!==t||t.overlay&&!t.$el.contains(e)||!t.panel||t.panel.contains(e)||z(document,`${_t} ${hi} scroll`,({defaultPrevented:i,type:s,target:n})=>{!i&&s===_t&&e===n&&t.hide()},!0)})}function $a(t){return w(document,"keydown",e=>{e.keyCode===27&&Wt(nt)===t&&t.hide()})}function Un(t,e){t!=null&&t.ariaExpanded&&(t.ariaExpanded=e)}var _s={slide:{show(t){return[{transform:j(t*-100)},{transform:j()}]},percent(t){return Je(t)},translate(t,e){return[{transform:j(e*-100*t)},{transform:j(e*100*(1-t))}]}}};function Je(t){return Math.abs(new DOMMatrix(h(t,"transform")).m41/t.offsetWidth)}function j(t=0,e="%"){return t?`translate3d(${t+e}, 0, 0)`:""}function ya(t,e,i,{animation:s,easing:n}){const{percent:o,translate:r,show:a=A}=s,l=a(i),{promise:c,resolve:u}=Vn();return{dir:i,show(d,f=0,p){const b=p?"linear":n;return d-=Math.round(d*K(f,-1,1)),this.translate(f),Zt(e,"itemin",{percent:f,duration:d,timing:b,dir:i}),Zt(t,"itemout",{percent:1-f,duration:d,timing:b,dir:i}),Promise.all([M.start(e,l[1],d,b),M.start(t,l[0],d,b)]).then(()=>{this.reset(),u()},A),c},cancel(){return M.cancel([e,t])},reset(){St([e,t],l[0])},async forward(d,f=this.percent()){return await this.cancel(),this.show(d,f,!0)},translate(d){this.reset();const f=r(d,i);h(e,f[1]),h(t,f[0]),Zt(e,"itemtranslatein",{percent:d,dir:i}),Zt(t,"itemtranslateout",{percent:1-d,dir:i})},percent(){return o(t||e,e,i)},getDistance(){return t==null?void 0:t.offsetWidth}}}function Zt(t,e,i){m(t,pe(e,!1,!1,i))}function Vn(){let t;return{promise:new Promise(e=>t=e),resolve:t}}var Ei={props:{i18n:Object},data:{i18n:null},methods:{t(t,...e){var i,s,n;let o=0;return((n=((i=this.i18n)==null?void 0:i[t])||((s=this.$options.i18n)==null?void 0:s[t]))==null?void 0:n.replace(/%s/g,()=>e[o++]||""))||""}}},ka={props:{autoplay:Boolean,autoplayInterval:Number,pauseOnHover:Boolean},data:{autoplay:!1,autoplayInterval:7e3,pauseOnHover:!0},connected(){k(this.list,"aria-live",this.autoplay?"off":"polite"),this.autoplay&&this.startAutoplay()},disconnected(){this.stopAutoplay()},update(){k(this.slides,"tabindex","-1")},events:[{name:"visibilitychange",el:()=>document,filter:({autoplay:t})=>t,handler(){document.hidden?this.stopAutoplay():this.startAutoplay()}}],methods:{startAutoplay(){this.stopAutoplay(),this.interval=setInterval(()=>{this.stack.length||this.draggable&&C(this.$el,":focus-within")&&!C(this.$el,":focus")||this.pauseOnHover&&C(this.$el,":hover")||this.show("next")},this.autoplayInterval)},stopAutoplay(){clearInterval(this.interval)}}};const Ti={passive:!1,capture:!0},Yn={passive:!0,capture:!0},Sa="touchstart mousedown",As="touchmove mousemove",Gn="touchend touchcancel mouseup click input scroll";var Ia={props:{draggable:Boolean},data:{draggable:!0,threshold:10},created(){for(const t of["start","move","end"]){const e=this[t];this[t]=i=>{const s=kt(i).x*(U?-1:1);this.prevPos=s===this.pos?this.prevPos:this.pos,this.pos=s,e(i)}}},events:[{name:Sa,passive:!0,delegate:({selList:t})=>`${t} > *`,handler(t){!this.draggable||this.parallax||!pt(t)&&Ea(t.target)||t.target.closest(De)||t.button>0||this.length<2||this.start(t)}},{name:"dragstart",handler(t){t.preventDefault()}},{name:As,el:({list:t})=>t,handler:A,...Ti}],methods:{start(){this.drag=this.pos,this._transitioner?(this.percent=this._transitioner.percent(),this.drag+=this._transitioner.getDistance()*this.percent*this.dir,this._transitioner.cancel(),this._transitioner.translate(this.percent),this.dragging=!0,this.stack=[]):this.prevIndex=this.index,w(document,As,this.move,Ti),w(document,Gn,this.end,Yn),h(this.list,"userSelect","none")},move(t){const e=this.pos-this.drag;if(e===0||this.prevPos===this.pos||!this.dragging&&Math.abs(e)r;)this.drag-=r*this.dir,s=o,n-=r,o=this.getIndex(s+this.dir),r=Xn.call(this,s,o);this.percent=n/r;const a=i[s],l=i[o],c=this.index!==o,u=s===o;let d;for(const f of[this.index,this.prevIndex])v([o,s],f)||(m(i[f],"itemhidden",[this]),u&&(d=!0,this.prevIndex=s));(this.index===s&&this.prevIndex!==s||d)&&m(i[this.index],"itemshown",[this]),c&&(this.prevIndex=s,this.index=o,u||(m(a,"beforeitemhide",[this]),m(a,"itemhide",[this])),m(l,"beforeitemshow",[this]),m(l,"itemshow",[this])),this._transitioner=this._translate(Math.abs(this.percent),a,!u&&l)},end(){if(Yt(document,As,this.move,Ti),Yt(document,Gn,this.end,Yn),this.dragging)if(setTimeout(w(this.list,"click",t=>t.preventDefault(),Ti)),this.dragging=null,this.index===this.prevIndex)this.percent=1-this.percent,this.dir*=-1,this._show(!1,this.index,!0),this._transitioner=null;else{const t=(U?this.dir*(U?1:-1):this.dir)<0==this.prevPos>this.pos;this.index=t?this.index:this.prevIndex,t&&(m(this.slides[this.prevIndex],"itemhidden",[this]),m(this.slides[this.index],"itemshown",[this]),this.percent=1-this.percent),this.show(this.dir>0&&!t||this.dir<0&&t?"next":"previous",!0)}h(this.list,{userSelect:""}),this.drag=this.percent=null}}};function Xn(t,e){return this._getTransitioner(t,t!==e&&e).getDistance()||this.slides[t].offsetWidth}function Ea(t){return h(t,"userSelect")!=="none"&&re(t.childNodes).some(e=>e.nodeType===3&&e.textContent.trim())}function Ta(t){t._watches=[];for(const e of t.$options.watch||[])for(const[i,s]of Object.entries(e))Jn(t,s,i);t._initial=!0}function Jn(t,e,i){t._watches.push({name:i,...Te(e)?e:{handler:e}})}function Ca(t,e){for(const{name:i,handler:s,immediate:n=!0}of t._watches)(t._initial&&n||gt(e,i)&&!Ae(e[i],t[i]))&&s.call(t,t[i],e[i]);t._initial=!1}function Pa(t){const{computed:e}=t.$options;if(t._computed={},e)for(const i in e)Zn(t,i,e[i])}const Kn={subtree:!0,childList:!0};function Zn(t,e,i){t._hasComputed=!0,Object.defineProperty(t,e,{enumerable:!0,get(){const{_computed:s,$props:n,$el:o}=t;if(!gt(s,e)&&(s[e]=(i.get||i).call(t,n,o),i.observe&&t._computedObserver)){const r=i.observe.call(t,n);t._computedObserver.observe(["~","+","-"].includes(r[0])?o.parentElement:o.getRootNode(),Kn)}return s[e]},set(s){const{_computed:n}=t;n[e]=i.set?i.set.call(t,s):s,X(n[e])&&delete n[e]}})}function _a(t){t._hasComputed&&(Qr(t,{read:()=>Ca(t,Qn(t)),events:["resize","computed"]}),t._computedObserver=rs(t.$el,()=>Ve(t,"computed"),Kn),t._disconnect.push(()=>{t._computedObserver.disconnect(),t._computedObserver=null,Qn(t)}))}function Qn(t){const e={...t._computed};return t._computed={},e}function Aa(t){for(const e of t.$options.events||[])if(gt(e,"handler"))to(t,e);else for(const i in e)to(t,{name:i,handler:e[i]})}function to(t,{name:e,el:i,handler:s,capture:n,passive:o,delegate:r,filter:a,self:l}){a&&!a.call(t,t)||t._disconnect.push(w(i?i.call(t,t):t.$el,e,r==null?void 0:r.call(t,t),s.bind(t),{passive:o,capture:n,self:l}))}function Oa(t){for(const e of t.$options.observe||[])Ma(t,e)}function Ma(t,e){let{observe:i,target:s=t.$el,handler:n,options:o,filter:r,args:a}=e;if(r&&!r.call(t,t))return;const l=`_observe${t._disconnect.length}`;ot(s)&&!gt(t,l)&&Zn(t,l,()=>{const d=s.call(t,t);return J(d)?E(d):d}),n=H(n)?t[n]:n.bind(t),ot(o)&&(o=o.call(t,t));const c=gt(t,l)?t[l]:s,u=i(c,n,o,a);ot(s)&&J(t[l])&&Jn(t,{handler:Da(u,o),immediate:!1},l),t._disconnect.push(()=>u.disconnect())}function Da(t,e){return(i,s)=>{for(const n of s)v(i,n)||(t.unobserve?t.unobserve(n):t.observe&&t.disconnect());for(const n of i)(!v(s,n)||!t.unobserve)&&t.observe(n,e)}}function Ba(t){const{$options:e,$props:i}=t,s=eo(e);ft(i,s);const{computed:n,methods:o}=e;for(let r in i)r in s&&(!n||!gt(n,r))&&(!o||!gt(o,r))&&(t[r]=i[r])}function eo(t){const e={},{args:i=[],props:s={},el:n,id:o}=t;if(!s)return e;for(const a in s){const l=Ft(a);let c=Z(n,l);X(c)||(c=s[a]===Boolean&&c===""?!0:vs(s[a],c),!(l==="target"&&wt(c,"_"))&&(e[a]=c))}const r=ve(Z(n,o),i);for(const a in r){const l=Ee(a);X(s[l])||(e[l]=vs(s[l],r[a]))}return e}const Na=ct((t,e)=>{const i=Object.keys(e),s=i.concat(t).map(n=>[Ft(n),`data-${Ft(n)}`]).flat();return{attributes:i,filter:s}});function za(t){const{$options:e,$props:i}=t,{id:s,props:n,el:o}=e;if(!n)return;const{attributes:r,filter:a}=Na(s,n),l=new MutationObserver(c=>{const u=eo(e);c.some(({attributeName:d})=>{const f=d.replace("data-","");return(f===s?r:[Ee(f),Ee(d)]).some(p=>!X(u[p])&&u[p]!==i[p])})&&t.$reset()});l.observe(o,{attributes:!0,attributeFilter:a}),t._disconnect.push(()=>l.disconnect())}function we(t,e){var i;(i=t.$options[e])==null||i.forEach(s=>s.call(t))}function Os(t){t._connected||(Ba(t),we(t,"beforeConnect"),t._connected=!0,t._disconnect=[],Aa(t),Zr(t),Ta(t),Oa(t),za(t),_a(t),we(t,"connected"),Ve(t))}function Ms(t){t._connected&&(we(t,"beforeDisconnect"),t._disconnect.forEach(e=>e()),t._disconnect=null,we(t,"disconnected"),t._connected=!1)}let Fa=0;function io(t,e={}){e.data=Wa(e,t.constructor.options),t.$options=Ue(t.constructor.options,e,t),t.$props={},t._uid=Fa++,Ha(t),La(t),Pa(t),we(t,"created"),e.el&&t.$mount(e.el)}function Ha(t){const{data:e={}}=t.$options;for(const i in e)t.$props[i]=t[i]=e[i]}function La(t){const{methods:e}=t.$options;if(e)for(const i in e)t[i]=e[i].bind(t)}function Wa({data:t={}},{args:e=[],props:i={}}){J(t)&&(t=t.slice(0,e.length).reduce((s,n,o)=>(Te(n)?ft(s,n):s[e[o]]=n,s),{}));for(const s in t)X(t[s])?delete t[s]:i[s]&&(t[s]=vs(i[s],t[s]));return t}const ht=function(t){io(this,t)};ht.util=Ur,ht.options={},ht.version="3.23.12";const ja="uk-",Qt="__uikit__",xe={};function so(t,e){var i,s;const n=ja+Ft(t);if(!e)return xe[n].options||(xe[n]=ht.extend(xe[n])),xe[n];t=Ee(t),ht[t]=(r,a)=>Ke(t,r,a);const o=(i=e.options)!=null?i:{...e};return o.id=n,o.name=t,(s=o.install)==null||s.call(o,ht,o,t),ht._initialized&&!o.functional&&requestAnimationFrame(()=>Ke(t,`[${n}],[data-${n}]`)),xe[n]=o}function Ke(t,e,i,...s){const n=so(t);return n.options.functional?new n({data:Te(e)?e:[e,i,...s]}):e?D(e).map(o)[0]:o();function o(r){const a=Ci(r,t);if(a)if(i)a.$destroy();else return a;return new n({el:r,data:i})}}function Ze(t){return(t==null?void 0:t[Qt])||{}}function Ci(t,e){return Ze(t)[e]}function Ra(t,e){t[Qt]||(t[Qt]={}),t[Qt][e.$options.name]=e}function qa(t,e){var i;(i=t[Qt])==null||delete i[e.$options.name],ni(t[Qt])&&delete t[Qt]}function Ua(t){t.component=so,t.getComponents=Ze,t.getComponent=Ci,t.update=no,t.use=function(i){if(!i.installed)return i.call(null,this),i.installed=!0,this},t.mixin=function(i,s){s=(H(s)?this.component(s):s)||this,s.options=Ue(s.options,i)},t.extend=function(i){i||(i={});const s=this,n=function(r){io(this,r)};return n.prototype=Object.create(s.prototype),n.prototype.constructor=n,n.options=Ue(s.options,i),n.super=s,n.extend=s.extend,n};let e;Object.defineProperty(t,"container",{get(){return e||document.body},set(i){e=x(i)}})}function no(t,e){t=t?R(t):document.body;for(const i of fe(t).reverse())oo(i,e);Mt(t,i=>oo(i,e))}function oo(t,e){const i=Ze(t);for(const s in i)Ve(i[s],e)}function Va(t){t.prototype.$mount=function(e){const i=this;Ra(e,i),i.$options.el=e,e.isConnected&&Os(i)},t.prototype.$destroy=function(e=!1){const i=this,{el:s}=i.$options;s&&Ms(i),we(i,"destroy"),qa(s,i),e&&Q(i.$el)},t.prototype.$create=Ke,t.prototype.$emit=function(e){Ve(this,e)},t.prototype.$update=function(e=this.$el,i){no(e,i)},t.prototype.$reset=function(){Ms(this),Os(this)},t.prototype.$getComponent=Ci,Object.defineProperties(t.prototype,{$el:{get(){return this.$options.el}},$container:Object.getOwnPropertyDescriptor(t,"container")})}let Ya=1;function te(t,e=null){return(e==null?void 0:e.id)||`${t.$options.id}-${Ya++}`}var Ga={i18n:{next:"Next slide",previous:"Previous slide",slideX:"Slide %s",slideLabel:"%s of %s",role:"String"},data:{selNav:!1,role:"region"},computed:{nav:({selNav:t},e)=>x(t,e),navChildren(){return N(this.nav)},selNavItem:({attrItem:t})=>`[${t}],[data-${t}]`,navItems(t,e){return D(this.selNavItem,e)}},watch:{nav(t,e){k(t,"role","tablist"),this.padNavitems(),e&&this.$emit()},list(t){F(t,"ul")&&k(t,"role","presentation")},navChildren(t){k(t,"role","presentation"),this.padNavitems(),this.updateNav()},navItems(t){for(const e of t){const i=Z(e,this.attrItem),s=x("a,button",e)||e;let n,o=null;if(mt(i)){const r=$t(i),a=this.slides[r];a&&(a.id||(a.id=te(this,a)),o=a.id),n=this.t("slideX",S(i)+1),s.role="tab"}else this.list&&(this.list.id||(this.list.id=te(this,this.list)),o=this.list.id),n=this.t(i);s.ariaControls=o,s.ariaLabel=s.ariaLabel||n}},slides(t){t.forEach((e,i)=>k(e,{role:this.nav?"tabpanel":"group","aria-label":this.t("slideLabel",i+1,this.length),"aria-roledescription":this.nav?null:"slide"})),this.padNavitems()}},connected(){this.$el.role=this.role,this.$el.ariaRoleDescription="carousel"},update:[{write(){this.navItems.concat(this.nav).forEach(t=>t&&(t.hidden=!this.maxIndex)),this.updateNav()},events:["resize"]}],events:[{name:"click keydown",delegate:({selNavItem:t})=>t,filter:({parallax:t})=>!t,handler(t){t.target.closest("a,button")&&(t.type==="click"||t.keyCode===B.SPACE)&&(Et(t),this.show(Z(t.current,this.attrItem)))}},{name:"itemshow",handler(){this.updateNav()}},{name:"keydown",delegate:({selNavItem:t})=>t,filter:({parallax:t})=>!t,handler(t){const{current:e,keyCode:i}=t,s=Z(e,this.attrItem);if(!mt(s))return;let n=i===B.HOME?0:i===B.END?"last":i===B.LEFT?"previous":i===B.RIGHT?"next":-1;~n&&(t.preventDefault(),this.show(n))}}],methods:{updateNav(){const t=this.getValidIndex();for(const e of this.navItems){const i=Z(e,this.attrItem),s=x("a,button",e)||e;if(mt(i)){const o=$t(i)===t;L(e,this.clsActive,o),L(s,"uk-disabled",!!this.parallax),s.ariaSelected=o,s.tabIndex=o&&!this.parallax?null:-1,o&&s&&C(O(e),":focus-within")&&s.focus()}else L(e,"uk-invisible",this.finite&&(i==="previous"&&t===0||i==="next"&&t>=this.maxIndex))}},padNavitems(){if(!this.nav)return;const t=[];for(let e=0;es.matches(`[${i}]`))||x(`
  • `)}Ae(t,this.navChildren)||vt(this.nav,t)}}};const Xa="cubic-bezier(0.25, 0.46, 0.45, 0.94)",Ja="cubic-bezier(0.165, 0.84, 0.44, 1)";var ro={mixins:[ka,Ia,Ga,Ei],props:{clsActivated:String,easing:String,index:Number,finite:Boolean,velocity:Number},data:()=>({easing:"ease",finite:!1,velocity:1,index:0,prevIndex:-1,stack:[],percent:0,clsActive:"uk-active",clsActivated:"",clsEnter:"uk-slide-enter",clsLeave:"uk-slide-leave",clsSlideActive:"uk-slide-active",Transitioner:!1,transitionOptions:{}}),connected(){this.prevIndex=-1,this.index=this.getValidIndex(this.$props.index),this.stack=[]},disconnected(){_(this.slides,this.clsActive)},computed:{duration:({velocity:t},e)=>ao(e.offsetWidth/t),list:({selList:t},e)=>x(t,e),maxIndex(){return this.length-1},slides(){return N(this.list)},length(){return this.slides.length}},watch:{slides(t,e){e&&this.$emit()}},events:{itemshow({target:t}){I(t,this.clsEnter,this.clsSlideActive)},itemshown({target:t}){_(t,this.clsEnter)},itemhide({target:t}){I(t,this.clsLeave)},itemhidden({target:t}){_(t,this.clsLeave,this.clsSlideActive)}},methods:{async show(t,e=!1){var i;if(this.dragging||!this.length||this.parallax)return;const{stack:s}=this,n=e?0:s.length,o=()=>{s.splice(n,1),s.length&&this.show(s.shift(),!0)};if(s[e?"unshift":"push"](t),!e&&s.length>1){s.length===2&&((i=this._transitioner)==null||i.forward(Math.min(this.duration,200)));return}const r=this.getIndex(this.index),a=$(this.slides,this.clsActive)&&this.slides[r],l=this.getIndex(t,this.index),c=this.slides[l];if(a===c){o();return}if(this.dir=Ka(t,r),this.prevIndex=r,this.index=l,a&&!m(a,"beforeitemhide",[this])||!m(c,"beforeitemshow",[this,a])){this.index=this.prevIndex,o();return}a&&m(a,"itemhide",[this]),m(c,"itemshow",[this]),await this._show(a,c,e),a&&m(a,"itemhidden",[this]),m(c,"itemshown",[this]),s.shift(),this._transitioner=null,s.length&&requestAnimationFrame(()=>s.length&&this.show(s.shift(),!0))},getIndex(t=this.index,e=this.index){return K(rt(t,this.slides,e,this.finite),0,Math.max(0,this.maxIndex))},getValidIndex(t=this.index,e=this.prevIndex){return this.getIndex(t,e)},async _show(t,e,i){if(this._transitioner=this._getTransitioner(t,e,this.dir,{easing:i?e.offsetWidth<600?Xa:Ja:this.easing,...this.transitionOptions}),!i&&!t){this._translate(1);return}const{length:s}=this.stack;return this._transitioner[s>1?"forward":"show"](s>1?Math.min(this.duration,75+75/(s-1)):this.duration,this.percent)},_translate(t,e=this.prevIndex,i=this.index){const s=this._getTransitioner(e===i?!1:e,i);return s.translate(t),s},_getTransitioner(t=this.prevIndex,e=this.index,i=this.dir||1,s=this.transitionOptions){return new this.Transitioner(_e(t)?this.slides[t]:t,_e(e)?this.slides[e]:e,i*(U?-1:1),s)}}};function Ka(t,e){return t==="next"?1:t==="previous"||t0?1-Je(e):Je(t)},translate(t,e){return e<0?[{transform:j(t*100),zIndex:0},{transform:j(-30*(1-t)),zIndex:-1}]:[{transform:j(-30*t),zIndex:-1},{transform:j(100*(1-t)),zIndex:0}]}}};function $e(t){return`scale3d(${t}, ${t}, 1)`}var ho={..._s,fade:{show(){return[{opacity:0},{opacity:1}]},percent(t){return 1-h(t,"opacity")},translate(t){return[{opacity:1-t},{opacity:t}]}},scale:{show(){return[{opacity:0,transform:$e(1-.2)},{opacity:1,transform:$e(1)}]},percent(t){return 1-h(t,"opacity")},translate(t){return[{opacity:1-t,transform:$e(1-.2*t)},{opacity:t,transform:$e(1-.2+.2*t)}]}}},co={i18n:{counter:"%s / %s"},mixins:[Ps,lo],functional:!0,props:{counter:Boolean,preload:Number,nav:Boolean,slidenav:Boolean,delayControls:Number,videoAutoplay:Boolean,template:String},data:()=>({counter:!1,preload:1,nav:!1,slidenav:!0,delayControls:3e3,videoAutoplay:!1,items:[],cls:"uk-open",clsPage:"uk-lightbox-page",clsFit:"uk-lightbox-items-fit",clsZoom:"uk-lightbox-zoom",attrItem:"uk-lightbox-item",selList:".uk-lightbox-items",selClose:".uk-close-large",selNav:".uk-lightbox-thumbnav, .uk-lightbox-dotnav",selCaption:".uk-lightbox-caption",selCounter:".uk-lightbox-counter",pauseOnHover:!1,velocity:2,Animations:ho,template:'
        '}),created(){let t=x(this.template);F(t,"template")&&(t=It(vt(t)));const e=x(this.selList,t),i=this.$props.nav;Q(D(this.selNav,t).filter(o=>!C(o,`.uk-${i}`)));for(const[o,r]of this.items.entries())W(e,"
        "),i==="thumbnav"&&Le(Qa(r,this.videoAutoplay),W(x(this.selNav,t),`
      • `));this.slidenav||Q(D(".uk-lightbox-slidenav",t)),this.counter||Q(x(this.selCounter,t)),I(e,this.clsFit);const s=x("[uk-close]",t),n=this.t("close");s&&n&&(s.dataset.i18n=JSON.stringify({label:n})),this.$mount(W(this.container,t))},events:[{name:"click",self:!0,filter:({bgClose:t})=>t,delegate:({selList:t})=>`${t} > *`,handler(t){t.defaultPrevented||this.hide()}},{name:"click",self:!0,delegate:({clsZoom:t})=>`.${t}`,handler(t){t.defaultPrevented||L(this.list,this.clsFit)}},{name:`${Me} ${ut} keydown`,filter:({delayControls:t})=>t,handler(){this.showControls()}},{name:"shown",self:!0,handler(){this.showControls()}},{name:"hide",self:!0,handler(){this.hideControls(),_(this.slides,this.clsActive),M.stop(this.slides)}},{name:"hidden",self:!0,handler(){this.$destroy(!0)}},{name:"keyup",el:()=>document,handler({keyCode:t}){if(!this.isToggled()||!this.draggable)return;let e=-1;t===B.LEFT?e="previous":t===B.RIGHT?e="next":t===B.HOME?e=0:t===B.END&&(e="last"),~e&&this.show(e)}},{name:"beforeitemshow",handler(t){vt(x(this.selCaption,this.$el),this.getItem().caption||""),vt(x(this.selCounter,this.$el),this.t("counter",this.index+1,this.slides.length));for(let e=-this.preload;e<=this.preload;e++)this.loadItem(this.index+e);this.isToggled()||(this.draggable=!1,t.preventDefault(),this.toggleElement(this.$el,!0,!1),this.animation=ho.scale,_(t.target,this.clsActive),this.stack.splice(1,0,this.index))}},{name:"itemshown",handler(){this.draggable=this.$props.draggable}},{name:"itemload",async handler(t,e){const{source:i,type:s,attrs:n={}}=e;if(this.setItem(e,""),!i)return;let o;const r={allowfullscreen:"",style:"max-width: 100%; box-sizing: border-box;","uk-responsive":"","uk-video":`${!!this.videoAutoplay}`};if(s==="image"||uo(i)){const a=Nt("img");Wn(a,e.sources),k(a,{src:i,...oi(e,["alt","srcset","sizes"]),...n}),w(a,"load",()=>this.setItem(e,O(a)||a)),w(a,"error",()=>this.setError(e))}else if(s==="video"||fo(i)){const a=this.videoAutoplay==="inline",l=Nt("video",{src:i,playsinline:"",controls:a?null:"",loop:a?"":null,poster:this.videoAutoplay?null:e.poster,"uk-video":a?"automute: true":!!this.videoAutoplay,...n});w(l,"loadedmetadata",()=>this.setItem(e,l)),w(l,"error",()=>this.setError(e))}else if(s==="iframe"||i.match(/\.(html|php)($|\?)/i))this.setItem(e,Nt("iframe",{src:i,allowfullscreen:"",class:"uk-lightbox-iframe",...n}));else if(o=i.match(/\/\/(?:.*?youtube(-nocookie)?\..*?(?:[?&]v=|\/shorts\/)|youtu\.be\/)([\w-]{11})[&?]?(.*)?/))this.setItem(e,Nt("iframe",{src:`https://www.youtube${o[1]||""}.com/embed/${o[2]}${o[3]?`?${o[3]}`:""}`,width:1920,height:1080,...r,...n}));else if(o=i.match(/\/\/.*?vimeo\.[a-z]+\/(\d+)[&?]?(.*)?/))try{const{height:a,width:l}=await(await fetch(`https://vimeo.com/api/oembed.json?maxwidth=1920&url=${encodeURI(i)}`,{credentials:"omit"})).json();this.setItem(e,Nt("iframe",{src:`https://player.vimeo.com/video/${o[1]}${o[2]?`?${o[2]}`:""}`,width:l,height:a,...r,...n}))}catch{this.setError(e)}}},{name:"itemloaded",handler(){this.$emit("resize")}}],update:{read(){for(const t of D(`${this.selList} :not([controls]):is(img,video)`,this.$el))L(t,this.clsZoom,(t.naturalHeight||t.videoHeight)-this.$el.offsetHeight>Math.max(0,(t.naturalWidth||t.videoWidth)-this.$el.offsetWidth))},events:["resize"]},methods:{loadItem(t=this.index){const e=this.getItem(t);this.getSlide(e).childElementCount||m(this.$el,"itemload",[e])},getItem(t=this.index){return this.items[rt(t,this.slides)]},setItem(t,e){m(this.$el,"itemloaded",[this,vt(this.getSlide(t),e)])},getSlide(t){return this.slides[this.items.indexOf(t)]},setError(t){this.setItem(t,'')},showControls(){clearTimeout(this.controlsTimer),this.controlsTimer=this.delayControls&&setTimeout(this.hideControls,this.delayControls),I(this.$el,"uk-active","uk-transition-active")},hideControls(){_(this.$el,"uk-active","uk-transition-active")}}};function Nt(t,e){const i=It(`<${t}>`);return k(i,e),i}function Qa(t,e){const i=t.poster||t.thumb&&(t.type==="image"||uo(t.thumb))?Nt("img",{src:t.poster||t.thumb,alt:""}):t.thumb&&(t.type==="video"||fo(t.thumb))?Nt("video",{src:t.thumb,loop:"",playsinline:"","uk-video":`autoplay: ${!!e}; automute: true`}):Nt("canvas");return t.thumbRatio&&(i.style.aspectRatio=t.thumbRatio),i}function uo(t){return t==null?void 0:t.match(/\.(avif|jpe?g|jfif|a?png|gif|svg|webp)($|\?)/i)}function fo(t){return t==null?void 0:t.match(/\.(mp4|webm|ogv)($|\?)/i)}const tl=".uk-disabled *, .uk-disabled, [disabled]";var el={install:il,props:{toggle:String},data:{toggle:"a"},computed:{toggles:({toggle:t},e)=>D(t,e)},watch:{toggles(t){this.hide();for(const e of t)F(e,"a")&&(e.role="button")}},disconnected(){this.hide()},events:{name:"click",delegate:({toggle:t})=>t,handler(t){t.defaultPrevented||(t.preventDefault(),C(t.current,tl)||this.show(t.current))}},methods:{show(t){let e=this.toggles.map(po);if(this.nav==="thumbnav"&&sl.call(this,this.toggles,e),e=Ys(e,"source"),ae(t)){const{source:i}=po(t);t=xt(e,({source:s})=>i===s)}return this.panel=this.panel||this.$create("lightboxPanel",{...this.$props,items:e}),w(this.panel.$el,"hidden",()=>this.panel=null),this.panel.show(t)},hide(){var t;return(t=this.panel)==null?void 0:t.hide()}}};function il(t,e){t.lightboxPanel||t.component("lightboxPanel",co),ft(e.props,t.component("lightboxPanel").options.props)}function sl(t,e){for(const[i,s]of Object.entries(t)){if(e[i].thumb)continue;const n=fe(s).reverse().concat(s).find(r=>this.$el.contains(r)&&(r===s||D(this.toggle,r).length===1));if(!n)continue;const o=x("img,video",n);o&&(e[i].thumb=o.currentSrc||o.poster||o.src,e[i].thumbRatio=(o.naturalWidth||o.videoWidth)/(o.naturalHeight||o.videoHeight))}}function po(t){const e={};for(const i of t.getAttributeNames()){const s=i.replace(/^data-/,"");e[s==="href"?"source":s]=t.getAttribute(i)}return e.attrs=ve(e.attrs),e}var nl={mixins:[Xe],functional:!0,args:["message","status"],data:{message:"",status:"",timeout:5e3,group:"",pos:"top-center",clsContainer:"uk-notification",clsClose:"uk-notification-close",clsMsg:"uk-notification-message"},install:ol,computed:{marginProp:({pos:t})=>`margin-${t.match(/[a-z]+(?=-)/)[0]}`,startProps(){return{opacity:0,[this.marginProp]:-this.$el.offsetHeight}}},created(){const t=`${this.clsContainer}-${this.pos}`,e=`data-${this.clsContainer}-container`,i=x(`.${t}[${e}]`,this.container)||W(this.container,`
        `);this.$mount(W(i,``))},async connected(){const t=S(h(this.$el,this.marginProp));await M.start(h(this.$el,this.startProps),{opacity:1,[this.marginProp]:t}),this.timeout&&(this.timer=setTimeout(this.close,this.timeout))},events:{click(t){Et(t),this.close()},[At](){this.timer&&clearTimeout(this.timer)},[Ut](){this.timeout&&(this.timer=setTimeout(this.close,this.timeout))}},methods:{async close(t){const e=i=>{const s=O(i);m(i,"close",[this]),Q(i),s!=null&&s.hasChildNodes()||Q(s)};this.timer&&clearTimeout(this.timer),t||await M.start(this.$el,this.startProps),e(this.$el)}}};function ol(t){t.notification.closeAll=function(e,i){Mt(document.body,s=>{const n=t.getComponent(s,"notification");n&&(!e||e===n.group)&&n.close(i)})}}var Pi={props:{media:Boolean},data:{media:!1},connected(){const t=rl(this.media,this.$el);if(this.matchMedia=!0,t){this.mediaObj=window.matchMedia(t);const e=()=>{this.matchMedia=this.mediaObj.matches,m(this.$el,pe("mediachange",!1,!0,[this.mediaObj]))};this.offMediaObj=w(this.mediaObj,"change",()=>{e(),this.$emit("resize")}),e()}},disconnected(){var t;(t=this.offMediaObj)==null||t.call(this)}};function rl(t,e){if(H(t)){if(wt(t,"@"))t=S(h(e,`--uk-breakpoint-${t.slice(1)}`));else if(isNaN(t))return t}return t&&mt(t)?`(min-width: ${t}px)`:""}function go(t){return q(t)?Math.ceil(Math.max(0,...D("[stroke]",t).map(e=>{var i;return((i=e.getTotalLength)==null?void 0:i.call(e))||0}))):0}const _i={x:Ai,y:Ai,rotate:Ai,scale:Ai,color:Ds,backgroundColor:Ds,borderColor:Ds,blur:ee,hue:ee,fopacity:ee,grayscale:ee,invert:ee,saturate:ee,sepia:ee,opacity:ll,stroke:hl,bgx:bo,bgy:bo},{keys:mo}=Object;var vo={mixins:[Pi],props:ko(mo(_i),"list"),data:ko(mo(_i),void 0),computed:{props(t,e){const i={};for(const n in t)n in _i&&!X(t[n])&&(i[n]=t[n].slice());const s={};for(const n in i)s[n]=_i[n](n,e,i[n],i);return s}},events:{load(){this.$emit()}},methods:{reset(){St(this.$el,this.getCss(0))},getCss(t){const e={};for(const i in this.props)this.props[i](e,K(t));return e.willChange=Object.keys(e).map(di).join(","),e}}};function Ai(t,e,i){let s=Mi(i)||{x:"px",y:"px",rotate:"deg"}[t]||"",n;return t==="x"||t==="y"?(t=`translate${Ht(t)}`,n=o=>S(S(o).toFixed(s==="px"?0:6))):t==="scale"&&(s="",n=o=>{var r;return Mi([o])?G(o,"width",e,!0)/e[`offset${(r=o.endsWith)!=null&&r.call(o,"vh")?"Height":"Width"}`]:S(o)}),i.length===1&&i.unshift(t==="scale"?1:0),i=ye(i,n),(o,r)=>{o.transform=`${o.transform||""} ${t}(${Qe(i,r)}${s})`}}function Ds(t,e,i){return i.length===1&&i.unshift(ti(e,t,"")),i=ye(i,s=>al(e,s)),(s,n)=>{const[o,r,a]=yo(i,n),l=o.map((c,u)=>(c+=a*(r[u]-c),u===3?S(c):parseInt(c,10))).join(",");s[t]=`rgba(${l})`}}function al(t,e){return ti(t,"color",e).split(/[(),]/g).slice(1,-1).concat(1).slice(0,4).map(S)}function ee(t,e,i){i.length===1&&i.unshift(0);const s=Mi(i)||{blur:"px",hue:"deg"}[t]||"%";return t={fopacity:"opacity",hue:"hue-rotate"}[t]||t,i=ye(i),(n,o)=>{const r=Qe(i,o);n.filter=`${n.filter||""} ${t}(${r+s})`}}function ll(t,e,i){return i.length===1&&i.unshift(ti(e,t,"")),i=ye(i),(s,n)=>{s[t]=Qe(i,n)}}function hl(t,e,i){i.length===1&&i.unshift(0);const s=Mi(i),n=go(e);return i=ye(i.reverse(),o=>(o=S(o),s==="%"?o*n/100:o)),i.some(([o])=>o)?(h(e,"strokeDasharray",n),(o,r)=>{o.strokeDashoffset=Qe(i,r)}):A}function bo(t,e,i,s){i.length===1&&i.unshift(0);const n=t==="bgy"?"height":"width";s[t]=ye(i,a=>G(a,n,e));const o=["bgx","bgy"].filter(a=>a in s);if(o.length===2&&t==="bgx")return A;if(ti(e,"backgroundSize","")==="cover")return cl(t,e,i,s);const r={};for(const a of o)r[a]=wo(e,a);return xo(o,r,s)}function cl(t,e,i,s){const n=ul(e);if(!n.width)return A;const o={width:e.offsetWidth,height:e.offsetHeight},r=["bgx","bgy"].filter(u=>u in s),a={};for(const u of r){const d=s[u].map(([P])=>P),f=Math.min(...d),p=Math.max(...d),b=d.indexOf(f){c(u,d),u.backgroundSize=`${l.width}px ${l.height}px`,u.backgroundRepeat="no-repeat"}}function wo(t,e){return ti(t,`background-position-${e.slice(-1)}`,"")}function xo(t,e,i){return function(s,n){for(const o of t){const r=Qe(i[o],n);s[`background-position-${o.slice(-1)}`]=`calc(${e[o]} + ${r}px)`}}}const $o={},Oi={};function ul(t){const e=h(t,"backgroundImage").replace(/^none|url\(["']?(.+?)["']?\)$/,"$1");if(Oi[e])return Oi[e];const i=new Image;return e&&(i.src=e,!i.naturalWidth&&!$o[e])?(z(i,"error load",()=>{Oi[e]=Bs(i),m(t,pe("load",!1))}),$o[e]=!0,Bs(i)):Oi[e]=Bs(i)}function Bs(t){return{width:t.naturalWidth,height:t.naturalHeight}}function ye(t,e=S){const i=[],{length:s}=t;let n=0;for(let o=0;o0;u--)i[o-u][1]=l+c*(n-u+1);n=0}}return i}function yo(t,e){const i=xt(t.slice(1),([,s])=>e<=s)+1;return[t[i-1][0],t[i][0],(e-t[i-1][1])/(t[i][1]-t[i-1][1])]}function Qe(t,e){const[i,s,n]=yo(t,e);return i+Math.abs(i-s)*n*(i(i[s]=e,i),{})}function So(t,e){return e>=0?Math.pow(t,e+1):1-Math.pow(1-t,1-e)}var fl={mixins:[vo],props:{target:String,viewport:Number,easing:Number,start:String,end:String},data:{target:!1,viewport:1,easing:1,start:0,end:0},computed:{target:({target:t},e)=>Io(t&&et(t,e)||e),start({start:t}){return G(t,"height",this.target,!0)},end({end:t,viewport:e}){return G(t||(e=(1-e)*100)&&`${e}vh+${e}%`,"height",this.target,!0)}},observe:[bs(),Ye({target:({target:t})=>t}),dt({target:({$el:t,target:e})=>[t,e,Bt(e,!0)]})],update:{read({percent:t},e){if(e.has("scroll")||(t=!1),!q(this.$el))return!1;if(!this.matchMedia)return;const i=t;return t=So(yi(this.target,this.start,this.end),this.easing),{percent:t,style:i===t?!1:this.getCss(t)}},write({style:t}){if(!this.matchMedia){this.reset();return}t&&h(this.$el,t)},events:["scroll","resize"]}};function Io(t){return t?"offsetTop"in t?t:Io(O(t)):document.documentElement}var Eo={props:{parallax:Boolean,parallaxTarget:Boolean,parallaxStart:String,parallaxEnd:String,parallaxEasing:Number},data:{parallax:!1,parallaxTarget:!1,parallaxStart:0,parallaxEnd:0,parallaxEasing:0},observe:[dt({target:({$el:t,parallaxTarget:e})=>[t,e],filter:({parallax:t})=>t}),Ye({filter:({parallax:t})=>t})],computed:{parallaxTarget({parallaxTarget:t},e){return t&&et(t,e)||this.list}},update:{read(){if(!this.parallax)return!1;const t=this.parallaxTarget;if(!t)return!1;const e=G(this.parallaxStart,"height",t,!0),i=G(this.parallaxEnd,"height",t,!0),s=So(yi(t,e,i),this.parallaxEasing);return{parallax:this.getIndexAt(s)}},write({parallax:t}){const[e,i]=t,s=this.getValidIndex(e+Math.ceil(i)),n=this.slides[e],o=this.slides[s],{triggerShow:r,triggerShown:a,triggerHide:l,triggerHidden:c}=pl(this);if(~this.prevIndex)for(const d of new Set([this.index,this.prevIndex]))v([s,e],d)||(l(this.slides[d]),c(this.slides[d]));const u=this.prevIndex!==e||this.index!==s;this.dir=1,this.prevIndex=e,this.index=s,n!==o&&l(n),r(o),u&&a(n),this._translate(n===o?1:i,n,o)},events:["scroll","resize"]},methods:{getIndexAt(t){const e=t*(this.length-1);return[Math.floor(e),e%1]}}};function pl(t){const{clsSlideActive:e,clsEnter:i,clsLeave:s}=t;return{triggerShow:n,triggerShown:o,triggerHide:r,triggerHidden:a};function n(l){$(l,s)&&(r(l),a(l)),$(l,e)||(m(l,"beforeitemshow",[t]),m(l,"itemshow",[t]))}function o(l){$(l,i)&&m(l,"itemshown",[t])}function r(l){$(l,e)||n(l),$(l,i)&&o(l),$(l,s)||(m(l,"beforeitemhide",[t]),m(l,"itemhide",[t]))}function a(l){$(l,s)&&m(l,"itemhidden",[t])}}var To={update:{write(){if(this.stack.length||this.dragging||this.parallax)return;const t=this.getValidIndex();!~this.prevIndex||this.index!==t?this.show(t):this._translate(1)},events:["resize"]}},Co={observe:Ii({target:({slides:t})=>t,targets:t=>t.getAdjacentSlides()}),methods:{getAdjacentSlides(){return[1,-1].map(t=>this.slides[this.getIndex(this.index+t)])}}};function gl(t,e,i,{center:s,easing:n,list:o}){const r=t?ei(t,o,s):ei(e,o,s)+g(e).width*i,a=e?ei(e,o,s):r+g(t).width*i*(U?-1:1),{promise:l,resolve:c}=Vn();return{dir:i,show(u,d=0,f){const p=f?"linear":n;return u-=Math.round(u*K(d,-1,1)),h(o,"transitionProperty","none"),this.translate(d),h(o,"transitionProperty",""),d=t?d:K(d,0,1),Zt(this.getItemIn(),"itemin",{percent:d,duration:u,timing:p,dir:i}),t&&Zt(this.getItemIn(!0),"itemout",{percent:1-d,duration:u,timing:p,dir:i}),M.start(o,{transform:j(-a*(U?-1:1),"px")},u,p).then(c,A),l},cancel(){return M.cancel(o)},reset(){h(o,"transform","")},async forward(u,d=this.percent()){return await this.cancel(),this.show(u,d,!0)},translate(u){if(u===this.percent())return;const d=this.getDistance()*i*(U?-1:1);h(o,"transform",j(K(-a+(d-d*u),-ke(o),g(o).width)*(U?-1:1),"px"));const f=this.getActives(),p=this.getItemIn(),b=this.getItemIn(!0);u=t?K(u,-1,1):0;for(const y of N(o)){const P=v(f,y),it=y===p,Tt=y===b,zt=it||!Tt&&(P||i*(U?-1:1)===-1^Di(y,o)>Di(t||e));Zt(y,`itemtranslate${zt?"in":"out"}`,{dir:i,percent:Tt?1-u:it?u:P?1:0})}},percent(){return Math.abs((new DOMMatrix(h(o,"transform")).m41*(U?-1:1)+r)/(a-r))},getDistance(){return Math.abs(a-r)},getItemIn(u=!1){let d=this.getActives(),f=_o(o,ei(e||t,o,s));if(u){const p=d;d=f,f=p}return f[xt(f,p=>!v(d,p))]},getActives(){return _o(o,ei(t||e,o,s))}}}function ei(t,e,i){const s=Di(t,e);return i?s-ml(t,e):Math.min(s,Po(e))}function Po(t){return Math.max(0,ke(t)-g(t).width)}function ke(t,e){return jt(N(t).slice(0,e),i=>g(i).width)}function ml(t,e){return g(e).width/2-g(t).width/2}function Di(t,e){return t&&(is(t).left+(U?g(t).width-g(e).width:0))*(U?-1:1)||0}function _o(t,e){e-=1;const i=g(t).width,s=e+i+2;return N(t).filter(n=>{const o=Di(n,t),r=o+Math.min(g(n).width,i);return o>=e&&r<=s})}var vl={mixins:[st,ro,To,Eo,Co],props:{center:Boolean,sets:Boolean,active:String},data:{center:!1,sets:!1,attrItem:"uk-slider-item",selList:".uk-slider-items",selNav:".uk-slider-nav",clsContainer:"uk-slider-container",active:"all",Transitioner:gl},computed:{finite({finite:t}){return t||bl(this.list,this.center)},maxIndex(){if(!this.finite||this.center&&!this.sets)return this.length-1;if(this.center)return Wt(this.sets);let t=0;const e=Po(this.list),i=xt(this.slides,s=>{if(t>=e-.005)return!0;t+=g(s).width});return~i?i:this.length-1},sets({sets:t}){if(!t||this.parallax)return;let e=0;const i=[],s=g(this.list).width;for(let n=0;ns&&(e=0),this.center?es/2&&(i.push(n),e=s/2-o/2):e===0&&i.push(Math.min(n,this.maxIndex)),e+=o}if(i.length)return i},transitionOptions(){return{center:this.center,list:this.list}},slides(){return N(this.list).filter(q)}},connected(){L(this.$el,this.clsContainer,!x(`.${this.clsContainer}`,this.$el))},observe:dt({target:({slides:t,$el:e})=>[e,...t]}),update:{write(){for(const t of this.navItems){const e=$t(Z(t,this.attrItem));e!==!1&&(t.hidden=!this.maxIndex||e>this.maxIndex||this.sets&&!v(this.sets,e))}this.reorder(),this.parallax||this._translate(1),this.updateActiveClasses()},events:["resize"]},events:{beforeitemshow(t){!this.dragging&&this.sets&&this.stack.length<2&&!v(this.sets,this.index)&&(this.index=this.getValidIndex());const e=Math.abs(this.index-this.prevIndex+(this.dir>0&&this.indexthis.prevIndex?(this.maxIndex+1)*this.dir:0));if(!this.dragging&&e>1){for(let n=0;n0?"next":"previous");t.preventDefault();return}const i=this.dir<0||!this.slides[this.prevIndex]?this.index:this.prevIndex,s=ke(this.list)/this.length;this.duration=ao(s/this.velocity)*(g(this.slides[i]).width/s),this.reorder()},itemshow(){~this.prevIndex&&I(this._getTransitioner().getItemIn(),this.clsActive),this.updateActiveClasses(this.prevIndex)},itemshown(){this.updateActiveClasses()}},methods:{reorder(){if(this.finite){h(this.slides,"order","");return}const t=this.dir>0&&this.slides[this.prevIndex]?this.prevIndex:this.index;if(this.slides.forEach((n,o)=>h(n,"order",this.dir>0&&o=this.index?-1:"")),!this.center||!this.length)return;const e=this.slides[t];let i=g(this.list).width/2-g(e).width/2,s=0;for(;i>0;){const n=this.getIndex(--s+t,t),o=this.slides[n];h(o,"order",n>t?-2:-1),i-=g(o).width}},updateActiveClasses(t=this.index){let e=this._getTransitioner(t).getActives();this.active!=="all"&&(e=[this.slides[this.getValidIndex(t)]]);const i=[this.clsActive,!this.sets||v(this.sets,S(this.index))?this.clsActivated:""];for(const s of this.slides){const n=v(e,s);L(s,i,n),s.ariaHidden=!n;for(const o of D(de,s))gt(o,"_tabindex")||(o._tabindex=o.tabIndex),o.tabIndex=n?o._tabindex:-1}},getValidIndex(t=this.index,e=this.prevIndex){if(t=this.getIndex(t,e),!this.sets)return t;let i;do{if(v(this.sets,t))return t;i=t,t=this.getIndex(t+this.dir,e)}while(t!==i);return t},getAdjacentSlides(){const{width:t}=g(this.list),e=-t,i=t*2,s=g(this.slides[this.index]).width,n=this.center?t/2-s/2:0,o=new Set;for(const r of[-1,1]){let a=n+(r>0?s:0),l=0;do{const c=this.slides[this.getIndex(this.index+r+l++*r)];a+=g(c).width*r,o.add(c)}while(this.length>l&&a>e&&a=0&&ejt(s.filter(u=>!l.has(u)),u=>g(u).width))return!0}return!1}function wl(t){return Math.max(0,...N(t).map(e=>g(e).width))}var Ao={mixins:[vo],beforeConnect(){this.item=this.$el.closest(`.${this.$options.id.replace("parallax","items")} > *`)},disconnected(){this.item=null},events:[{name:"itemin itemout",self:!0,el:({item:t})=>t,handler({type:t,detail:{percent:e,duration:i,timing:s,dir:n}}){Dt.read(()=>{if(!this.matchMedia)return;const o=this.getCss(Mo(t,n,e)),r=this.getCss(Oo(t)?.5:n>0?1:0);Dt.write(()=>{h(this.$el,o),M.start(this.$el,r,i,s).catch(A)})})}},{name:"transitioncanceled transitionend",self:!0,el:({item:t})=>t,handler(){M.cancel(this.$el)}},{name:"itemtranslatein itemtranslateout",self:!0,el:({item:t})=>t,handler({type:t,detail:{percent:e,dir:i}}){Dt.read(()=>{if(!this.matchMedia){this.reset();return}const s=this.getCss(Mo(t,i,e));Dt.write(()=>h(this.$el,s))})}}]};function Oo(t){return oe(t,"in")}function Mo(t,e,i){return i/=2,Oo(t)^e<0?i:1-i}var xl={mixins:[st,lo,To,Eo,Co],props:{ratio:String,minHeight:String,maxHeight:String},data:{ratio:"16:9",minHeight:void 0,maxHeight:void 0,selList:".uk-slideshow-items",attrItem:"uk-slideshow-item",selNav:".uk-slideshow-nav",Animations:Za},watch:{list(t){h(t,{aspectRatio:this.ratio?this.ratio.replace(":","/"):void 0,minHeight:this.minHeight,maxHeight:this.maxHeight,width:"100%"})}},methods:{getAdjacentSlides(){return[1,-1].map(t=>this.slides[this.getIndex(this.index+t)])}}},$l={mixins:[st,zn],props:{group:String,threshold:Number,clsItem:String,clsPlaceholder:String,clsDrag:String,clsDragState:String,clsBase:String,clsNoDrag:String,clsEmpty:String,clsCustom:String,handle:String},data:{group:!1,threshold:5,clsItem:"uk-sortable-item",clsPlaceholder:"uk-sortable-placeholder",clsDrag:"uk-sortable-drag",clsDragState:"uk-drag",clsBase:"uk-sortable",clsNoDrag:"uk-sortable-nodrag",clsEmpty:"uk-sortable-empty",clsCustom:"",handle:!1,pos:{}},events:{name:ut,passive:!1,handler(t){this.init(t)}},computed:{target:(t,e)=>(e.tBodies||[e])[0],items(){return N(this.target)},isEmpty(){return!this.items.length},handles({handle:t},e){return t?D(t,e):this.items}},watch:{isEmpty(t){L(this.target,this.clsEmpty,t)},handles(t,e){const i={touchAction:"none",userSelect:"none"};St(e,i),h(t,i)}},update:{write(t){if(!this.drag||!O(this.placeholder))return;const{pos:{x:e,y:i},origin:{offsetTop:s,offsetLeft:n},placeholder:o}=this;h(this.drag,{top:i-s,left:e-n});const r=this.getSortable(document.elementFromPoint(e,i));if(!r)return;const{items:a}=r;if(a.some(M.inProgress))return;const l=Il(a,{x:e,y:i});if(a.length&&(!l||l===o))return;const c=this.getSortable(o),u=El(r.target,l,o,e,i,r===c&&t.moved!==l);u!==!1&&(u&&o===u||(r!==c?(c.remove(o),t.moved=l):delete t.moved,r.insert(o,u),this.touched.add(r)))},events:["move"]},methods:{init(t){const{target:e,button:i,defaultPrevented:s}=t,[n]=this.items.filter(o=>o.contains(e));!n||s||i>0||ci(e)||e.closest(`.${this.clsNoDrag}`)||this.handle&&!e.closest(this.handle)||(t.preventDefault(),this.pos=kt(t),this.touched=new Set([this]),this.placeholder=n,this.origin={target:e,index:yt(n),...this.pos},w(document,Me,this.move),w(document,_t,this.end),this.threshold||this.start(t))},start(t){this.drag=Sl(this.$container,this.placeholder);const{left:e,top:i}=g(this.placeholder);ft(this.origin,{offsetLeft:this.pos.x-e,offsetTop:this.pos.y-i}),I(this.drag,this.clsDrag,this.clsCustom),I(this.placeholder,this.clsPlaceholder),I(this.items,this.clsItem),I(document.documentElement,this.clsDragState),m(this.$el,"start",[this,this.placeholder]),yl(this.pos),this.move(t)},move:Cl(function(t){ft(this.pos,kt(t)),!this.drag&&(Math.abs(this.pos.x-this.origin.x)>this.threshold||Math.abs(this.pos.y-this.origin.y)>this.threshold)&&this.start(t),this.$emit("move")}),end(){if(Yt(document,Me,this.move),Yt(document,_t,this.end),!this.drag)return;kl();const t=this.getSortable(this.placeholder);this===t?this.origin.index!==yt(this.placeholder)&&m(this.$el,"moved",[this,this.placeholder]):(m(t.$el,"added",[t,this.placeholder]),m(this.$el,"removed",[this,this.placeholder])),m(this.$el,"stop",[this,this.placeholder]),Q(this.drag),this.drag=null;for(const{clsPlaceholder:e,clsItem:i}of this.touched)for(const s of this.touched)_(s.items,e,i);this.touched=null,_(document.documentElement,this.clsDragState)},insert(t,e){I(this.items,this.clsItem),e&&e.previousElementSibling!==t?this.animate(()=>pi(e,t)):!e&&this.target.lastElementChild!==t&&this.animate(()=>W(this.target,t))},remove(t){this.target.contains(t)&&this.animate(()=>Q(t))},getSortable(t){do{const e=this.$getComponent(t,"sortable");if(e&&(e===this||this.group!==!1&&e.group===this.group))return e}while(t=O(t))}}};let Do;function yl(t){let e=Date.now();Do=setInterval(()=>{let{x:i,y:s}=t;s+=document.scrollingElement.scrollTop;const n=(Date.now()-e)*.3;e=Date.now(),Xt(document.elementFromPoint(i,t.y)).reverse().some(o=>{let{scrollTop:r,scrollHeight:a}=o;const{top:l,bottom:c,height:u}=at(o);if(ls)r-=n;else if(c>s&&c-350&&r"),W(i,e.cloneNode(!0).children);for(const s of e.getAttributeNames())k(i,s,e.getAttribute(s))}else i=e.cloneNode(!0);return W(t,i),h(i,"margin","0","important"),h(i,{boxSizing:"border-box",width:e.offsetWidth,height:e.offsetHeight,padding:h(e,"padding")}),tt(i.firstElementChild,tt(e.firstElementChild)),i}function Il(t,e){return t[xt(t,i=>ai(e,g(i)))]}function El(t,e,i,s,n,o){if(!N(t).length)return;const r=g(e);if(!o)return Tl(t,i)||nr[f]-p?!1:e}function Tl(t,e){const i=N(t).length===1;i&&W(t,e);const s=N(t),n=s.some((o,r)=>{const a=g(o);return s.slice(r+1).some(l=>{const c=g(l);return!Bo([a.left,a.right],[c.left,c.right])})});return i&&Q(e),n}function Bo(t,e){return t[1]>e[0]&&e[1]>t[0]}function Cl(t){let e;return function(...i){e||(e=!0,t.call(this,...i),requestAnimationFrame(()=>e=!1))}}var Pl={mixins:[Xe,Kt,Rn],data:{pos:"top",animation:["uk-animation-scale-up"],duration:100,cls:"uk-active"},connected(){_l(this.$el)},disconnected(){this.hide()},methods:{show(){if(this.isToggled(this.tooltip||null))return;const{delay:t=0,title:e}=Ol(this.$options);if(!e)return;const i=k(this.$el,"title"),s=w(this.$el,["blur",Ut],o=>!pt(o)&&this.hide());this.reset=()=>{k(this.$el,{title:i,"aria-describedby":null}),s()};const n=te(this);k(this.$el,{title:null,"aria-describedby":n}),clearTimeout(this.showTimer),this.showTimer=setTimeout(()=>this._show(e,n),t)},async hide(){var t;C(this.$el,"input:focus")||(clearTimeout(this.showTimer),this.isToggled(this.tooltip||null)&&await this.toggleElement(this.tooltip,!1,!1),(t=this.reset)==null||t.call(this),Q(this.tooltip),this.tooltip=null)},async _show(t,e){this.tooltip=W(this.container,``),w(this.tooltip,"toggled",(i,s)=>{if(!s)return;const n=()=>this.positionAt(this.tooltip,this.$el);n();const[o,r]=Al(this.tooltip,this.$el,this.pos);this.origin=this.axis==="y"?`${bi(o)}-${r}`:`${r}-${bi(o)}`;const a=[z(document,`keydown ${ut}`,this.hide,!1,l=>l.type===ut&&!this.$el.contains(l.target)||l.type==="keydown"&&l.keyCode===B.ESC),w([document,...Jt(this.$el)],"scroll",n,{passive:!0})];z(this.tooltip,"hide",()=>a.forEach(l=>l()),{self:!0})}),await this.toggleElement(this.tooltip,!0)||this.hide()}},events:{[`focus ${At} ${ut}`](t){(!pt(t)||t.type===ut)&&document.readyState!=="loading"&&this.show()}}};function _l(t){Be(t)||(t.tabIndex=0)}function Al(t,e,[i,s]){const n=T(t),o=T(e),r=[["left","right"],["top","bottom"]];for(const l of r){if(n[l[0]]>=o[l[1]]){i=l[1];break}if(n[l[1]]<=o[l[0]]){i=l[0];break}}return s=(v(r[0],i)?r[1]:r[0]).find(l=>n[l]===o[l])||"center",[i,s]}function Ol(t){const{el:e,id:i,data:s}=t;return["delay","title"].reduce((n,o)=>({[o]:Z(e,o),...n}),{...ve(Z(e,i),["title"]),...s})}var Ml={mixins:[Ei],i18n:{invalidMime:"Invalid File Type: %s",invalidName:"Invalid File Name: %s",invalidSize:"Invalid File Size: %s Kilobytes Max"},props:{allow:String,clsDragover:String,concurrent:Number,maxSize:Number,method:String,mime:String,multiple:Boolean,name:String,params:Object,type:String,url:String},data:{allow:!1,clsDragover:"uk-dragover",concurrent:1,maxSize:0,method:"POST",mime:!1,multiple:!1,name:"files[]",params:{},type:"",url:"",abort:A,beforeAll:A,beforeSend:A,complete:A,completeAll:A,error:A,fail:A,load:A,loadEnd:A,loadStart:A,progress:A},events:{change(t){C(t.target,'input[type="file"]')&&(t.preventDefault(),t.target.files&&this.upload(t.target.files),t.target.value="")},drop(t){Bi(t);const e=t.dataTransfer;e!=null&&e.files&&(_(this.$el,this.clsDragover),this.upload(e.files))},dragenter(t){Bi(t)},dragover(t){Bi(t),I(this.$el,this.clsDragover)},dragleave(t){Bi(t),_(this.$el,this.clsDragover)}},methods:{async upload(t){if(t=re(t),!t.length)return;m(this.$el,"upload",[t]);for(const s of t){if(this.maxSize&&this.maxSize*1e3{const n=new FormData;s.forEach(o=>n.append(this.name,o));for(const o in this.params)n.append(o,this.params[o]);try{const o=await Bl(this.url,{data:n,method:this.method,responseType:this.type,beforeSend:r=>{const{xhr:a}=r;w(a.upload,"progress",this.progress);for(const l of["loadStart","load","loadEnd","abort"])w(a,l.toLowerCase(),this[l]);return this.beforeSend(r)}});this.complete(o),e.length?await i(e.shift()):this.completeAll(o)}catch(o){this.error(o)}};await i(e.shift())}}};function No(t,e){return e.match(new RegExp(`^${t.replace(/\//g,"\\/").replace(/\*\*/g,"(\\/[^\\/]+)*").replace(/\*/g,"[^\\/]+").replace(/((?!\\))\?/g,"$1.")}$`,"i"))}function Dl(t,e){const i=[];for(let s=0;s{const{xhr:n}=e;for(const o in e)if(o in n)try{n[o]=e[o]}catch{}n.open(e.method.toUpperCase(),t);for(const o in e.headers)n.setRequestHeader(o,e.headers[o]);w(n,"load",()=>{n.status===0||n.status>=200&&n.status<300||n.status===304?i(n):s(ft(Error(n.statusText),{xhr:n,status:n.status}))}),w(n,"error",()=>s(ft(Error("Network Error"),{xhr:n}))),w(n,"timeout",()=>s(ft(Error("Network Timeout"),{xhr:n}))),n.send(e.data)})}var zl=Object.freeze({__proto__:null,Countdown:Yr,Filter:oa,Lightbox:el,LightboxPanel:co,Notification:nl,Parallax:fl,Slider:vl,SliderParallax:Ao,Slideshow:xl,SlideshowParallax:Ao,Sortable:$l,Tooltip:Pl,Upload:Ml});function Fl(t){qt&&window.MutationObserver&&(document.body?requestAnimationFrame(()=>zo(t)):new MutationObserver((e,i)=>{document.body&&(zo(t),i.disconnect())}).observe(document.documentElement,{childList:!0}))}function zo(t){m(document,"uikit:init",t),document.body&&Mt(document.body,Fo),new MutationObserver(Hl).observe(document,{subtree:!0,childList:!0,attributes:!0}),t._initialized=!0}function Hl(t){var e;for(const{addedNodes:i,removedNodes:s,target:n,attributeName:o}of t){for(const a of i)Mt(a,Fo);for(const a of s)Mt(a,Ll);const r=o&&Ho(o);r&&(Pt(n,o)?Ke(r,n):(e=Ci(n,r))==null||e.$destroy())}}function Fo(t){const e=Ze(t);for(const i in e)Os(e[i]);for(const i of t.getAttributeNames()){const s=Ho(i);s&&Ke(s,t)}}function Ll(t){const e=Ze(t);for(const i in e)Ms(e[i])}function Ho(t){wt(t,"data-")&&(t=t.slice(5));const e=xe[t];return e&&(e.options||e).name}Ua(ht),Va(ht);var Lo={mixins:[st,Kt],props:{animation:Boolean,targets:String,active:null,collapsible:Boolean,multiple:Boolean,toggle:String,content:String,offset:Number},data:{targets:"> *",active:!1,animation:!0,collapsible:!0,multiple:!1,clsOpen:"uk-open",toggle:"> .uk-accordion-title",content:"> .uk-accordion-content",offset:0},computed:{items:({targets:t},e)=>D(t,e),toggles({toggle:t}){return this.items.map(e=>x(t,e))},contents({content:t}){return this.items.map(e=>{var i;return((i=e._wrapper)==null?void 0:i.firstElementChild)||x(t,e)})}},watch:{items(t,e){if(e||$(t,this.clsOpen))return;const i=this.active!==!1&&t[Number(this.active)]||!this.collapsible&&t[0];i&&this.toggle(i,!1)},toggles(){this.$emit()},contents(t){for(const e of t){const i=$(this.items.find(s=>s.contains(e)),this.clsOpen);Ni(e,!i)}this.$emit()}},observe:Ii(),events:[{name:"click keydown",delegate:({targets:t,$props:e})=>`${t} ${e.toggle}`,async handler(t){var e;t.type==="keydown"&&t.keyCode!==B.SPACE||(Et(t),(e=this._off)==null||e.call(this),this._off=jl(t.target),await this.toggle(yt(this.toggles,t.current)),this._off())}},{name:"shown hidden",self:!0,delegate:({targets:t})=>t,handler(){this.$emit()}}],update(){const t=Ne(this.items,`.${this.clsOpen}`);for(const e in this.items){const i=this.toggles[e],s=this.contents[e];if(!i||!s)continue;i.id=te(this,i),s.id=te(this,s);const n=v(t,this.items[e]);k(i,{role:F(i,"a")?"button":null,"aria-controls":s.id,"aria-expanded":n,"aria-disabled":!this.collapsible&&t.length<2&&n}),k(s,{role:"region","aria-labelledby":i.id}),F(s,"ul")&&k(N(s),"role","presentation")}},methods:{toggle(t,e){t=this.items[rt(t,this.items)];let i=[t];const s=Ne(this.items,`.${this.clsOpen}`);if(!this.multiple&&!v(s,i[0])&&(i=i.concat(s)),!(!this.collapsible&&s.length<2&&v(s,t)))return Promise.all(i.map(n=>this.toggleElement(n,!v(s,n),(o,r)=>{if(L(o,this.clsOpen,r),e===!1||!this.animation){Ni(x(this.content,o),!r);return}return Wl(o,r,this)})))}}};function Ni(t,e){t&&(t.hidden=e)}async function Wl(t,e,{content:i,duration:s,velocity:n,transition:o}){var r;i=((r=t._wrapper)==null?void 0:r.firstElementChild)||x(i,t),t._wrapper||(t._wrapper=Le(i,"
        "));const a=t._wrapper;h(a,"overflow","hidden");const l=S(h(a,"height"));await M.cancel(a),Ni(i,!1);const c=jt(["marginTop","marginBottom"],d=>h(i,d))+g(i).height,u=l/c;s=(n*c+s)*(e?1-u:u),h(a,"height",l),await M.start(a,{height:e?c:0},s,o),We(i),delete t._wrapper,e||Ni(i,!0)}function jl(t){const e=Bt(t,!0);let i;return function s(){i=requestAnimationFrame(()=>{const{top:n}=g(t);n<0&&(e.scrollTop+=n),s()})}(),()=>requestAnimationFrame(()=>cancelAnimationFrame(i))}var Rl={mixins:[st,Kt],args:"animation",props:{animation:Boolean,close:String},data:{animation:!0,selClose:".uk-alert-close",duration:150},events:{name:"click",delegate:({selClose:t})=>t,handler(t){Et(t),this.close()}},methods:{async close(){await this.toggleElement(this.$el,!1,ql),this.$destroy(!0)}}};function ql(t,e,{duration:i,transition:s,velocity:n}){const o=S(h(t,"height"));return h(t,"height",o),M.start(t,{height:0,marginTop:0,marginBottom:0,paddingTop:0,paddingBottom:0,borderTop:0,borderBottom:0,opacity:0},n*o+i,s)}var Wo={args:"autoplay",props:{automute:Boolean,autoplay:Boolean},data:{automute:!1,autoplay:!0},beforeConnect(){this.autoplay==="inview"&&!Pt(this.$el,"preload")&&(this.$el.preload="none"),F(this.$el,"iframe")&&!Pt(this.$el,"allow")&&(this.$el.allow="autoplay"),this.autoplay==="hover"&&(F(this.$el,"video")?this.$el.tabIndex=0:this.autoplay=!0),this.automute&&pn(this.$el)},events:[{name:`${At} focusin`,filter:({autoplay:t})=>v(t,"hover"),handler(t){!pt(t)||!Ul(this.$el)?as(this.$el):$i(this.$el)}},{name:`${Ut} focusout`,filter:({autoplay:t})=>v(t,"hover"),handler(t){pt(t)||$i(this.$el)}}],observe:[be({filter:({autoplay:t})=>t!=="hover",handler([{isIntersecting:t}]){document.fullscreenElement||(t?this.autoplay&&as(this.$el):$i(this.$el))},args:{intersecting:!1},options:({$el:t,autoplay:e})=>({root:e==="inview"?null:O(t).closest(":not(a)")})})]};function Ul(t){return!t.paused&&!t.ended}var Vl={mixins:[Wo],props:{width:Number,height:Number},data:{automute:!0},created(){this.useObjectFit=F(this.$el,"img","video")},observe:dt({target:({$el:t})=>jo(t)||O(t),filter:({useObjectFit:t})=>!t}),update:{read(){if(this.useObjectFit)return!1;const{$el:t,width:e=t.clientWidth,height:i=t.clientHeight}=this,s=jo(t)||O(t),n=Ui.cover({width:e,height:i},{width:s.offsetWidth,height:s.offsetHeight});return n.width&&n.height?n:!1},write({height:t,width:e}){h(this.$el,{height:t,width:e})},events:["resize"]}};function jo(t){for(;t=O(t);)if(h(t,"position")!=="static")return t}let Y;var Ro={mixins:[Xe,Rn,Kt],args:"pos",props:{mode:"list",toggle:Boolean,boundary:Boolean,boundaryX:Boolean,boundaryY:Boolean,target:Boolean,targetX:Boolean,targetY:Boolean,stretch:Boolean,delayShow:Number,delayHide:Number,autoUpdate:Boolean,clsDrop:String,animateOut:Boolean,bgScroll:Boolean,closeOnScroll:Boolean},data:{mode:["click","hover"],toggle:"- *",boundary:!1,boundaryX:!1,boundaryY:!1,target:!1,targetX:!1,targetY:!1,stretch:!1,delayShow:0,delayHide:800,autoUpdate:!0,clsDrop:!1,animateOut:!1,bgScroll:!0,animation:["uk-animation-fade"],cls:"uk-open",container:!1,closeOnScroll:!1,selClose:".uk-drop-close"},computed:{boundary({boundary:t,boundaryX:e,boundaryY:i},s){return[et(e||t,s)||window,et(i||t,s)||window]},target({target:t,targetX:e,targetY:i},s){return e||(e=t||this.targetEl),i||(i=t||this.targetEl),[e===!0?window:et(e,s),i===!0?window:et(i,s)]}},created(){this.tracker=new un},beforeConnect(){this.clsDrop=this.$props.clsDrop||this.$options.id},connected(){I(this.$el,"uk-drop",this.clsDrop),this.toggle&&!this.targetEl&&(this.targetEl=Gl(this)),k(this.targetEl,"aria-expanded",!1),this._style=oi(this.$el.style,["width","height"])},disconnected(){this.isActive()&&(this.hide(!1),Y=null),h(this.$el,this._style)},events:[{name:"click",delegate:({selClose:t})=>t,handler(t){Et(t),this.hide(!1)}},{name:"click",delegate:()=>'a[href*="#"]',handler({defaultPrevented:t,current:e}){const{hash:i}=e;!t&&i&&Vt(e)&&!this.$el.contains(x(i))&&this.hide(!1)}},{name:"beforescroll",handler(){this.hide(!1)}},{name:"toggle",self:!0,handler(t,e){t.preventDefault(),this.isToggled()?this.hide(!1):this.show(e==null?void 0:e.$el,!1)}},{name:"toggleshow",self:!0,handler(t,e){t.preventDefault(),this.show(e==null?void 0:e.$el)}},{name:"togglehide",self:!0,handler(t){t.preventDefault(),C(this.$el,":focus,:hover")||this.hide()}},{name:`${At} focusin`,filter:({mode:t})=>v(t,"hover"),handler(t){pt(t)||this.clearTimers()}},{name:`${Ut} focusout`,filter:({mode:t})=>v(t,"hover"),handler(t){!pt(t)&&t.relatedTarget&&this.hide()}},{name:"toggled",self:!0,handler(t,e){e&&(this.clearTimers(),this.position())}},{name:"show",self:!0,handler(){Y=this,this.tracker.init(),k(this.targetEl,"aria-expanded",!0);const t=[Xl(this),Jl(this),Zl(this),this.autoUpdate&&qo(this),this.closeOnScroll&&Kl(this)];z(this.$el,"hide",()=>t.forEach(e=>e&&e()),{self:!0}),this.bgScroll||z(this.$el,"hidden",jn(this.$el),{self:!0})}},{name:"beforehide",self:!0,handler(){this.clearTimers()}},{name:"hide",handler({target:t}){if(this.$el!==t){Y=Y===null&&this.$el.contains(t)&&this.isToggled()?this:Y;return}Y=this.isActive()?null:Y,this.tracker.cancel(),k(this.targetEl,"aria-expanded",!1)}}],update:{write(){this.isToggled()&&!$(this.$el,this.clsEnter)&&this.position()}},methods:{show(t=this.targetEl,e=!0){if(this.isToggled()&&t&&this.targetEl&&t!==this.targetEl&&this.hide(!1,!1),this.targetEl=t,this.clearTimers(),!this.isActive()){if(Y){if(e&&Y.isDelaying()){this.showTimer=setTimeout(()=>C(t,":hover")&&this.show(),10);return}let i;for(;Y&&i!==Y&&!Y.$el.contains(this.$el);)i=Y,Y.hide(!1,!1)}this.container&&O(this.$el)!==this.container&&W(this.container,this.$el),this.showTimer=setTimeout(()=>this.toggleElement(this.$el,!0),e&&this.delayShow||0)}},hide(t=!0,e=!0){const i=()=>this.toggleElement(this.$el,!1,this.animateOut&&e);this.clearTimers(),this.isDelayedHide=t,t&&this.isDelaying()?this.hideTimer=setTimeout(this.hide,50):t&&this.delayHide?this.hideTimer=setTimeout(i,this.delayHide):i()},clearTimers(){clearTimeout(this.showTimer),clearTimeout(this.hideTimer),this.showTimer=null,this.hideTimer=null},isActive(){return Y===this},isDelaying(){return[this.$el,...D(".uk-drop",this.$el)].some(t=>this.tracker.movesTo(t))},position(){const t=Cs(this.$el);_(this.$el,"uk-drop-stack"),h(this.$el,this._style),this.$el.hidden=!0;const e=this.target.map(o=>Yl(this.$el,o)),i=this.getViewportOffset(this.$el),s=[[0,["x","width","left","right"]],[1,["y","height","top","bottom"]]];for(const[o,[r,a]]of s)this.axis!==r&&v([r,!0],this.stretch)&&h(this.$el,{[a]:Math.min(T(this.boundary[o])[a],e[o][a]-2*i),[`overflow-${r}`]:"auto"});const n=e[0].width-2*i;this.$el.hidden=!1,h(this.$el,"maxWidth",""),this.$el.offsetWidth>n&&I(this.$el,"uk-drop-stack"),h(this.$el,"maxWidth",n),this.positionAt(this.$el,this.target,this.boundary);for(const[o,[r,a,l,c]]of s)if(this.axis===r&&v([r,!0],this.stretch)){const u=Math.abs(this.getPositionOffset()),d=T(this.target[o]),f=T(this.$el);h(this.$el,{[a]:(d[l]>f[l]?d[this.inset?c:l]-Math.max(T(this.boundary[o])[l],e[o][l]+i):Math.min(T(this.boundary[o])[c],e[o][c]-i)-d[this.inset?l:c])-u,[`overflow-${r}`]:"auto"}),this.positionAt(this.$el,this.target,this.boundary)}t()}}};function Yl(t,e){return at(Jt(e).find(i=>i.contains(t)))}function Gl(t){const{$el:e}=t.$create("toggle",et(t.toggle,t.$el),{target:t.$el,mode:t.mode});return e.ariaHasPopup=!0,e}function Xl(t){const e=()=>t.$emit(),i=[os(e),qe(Jt(t.$el).concat(t.target),e)];return()=>i.map(s=>s.disconnect())}function qo(t,e=()=>t.$emit()){return w([document,...Jt(t.$el)],"scroll",e,{passive:!0})}function Jl(t){return w(document,"keydown",e=>{e.keyCode===B.ESC&&t.hide(!1)})}function Kl(t){return qo(t,()=>t.hide(!1))}function Zl(t){return w(document,ut,({target:e})=>{t.$el.contains(e)||z(document,`${_t} ${hi} scroll`,({defaultPrevented:i,type:s,target:n})=>{var o;!i&&s===_t&&e===n&&!((o=t.targetEl)!=null&&o.contains(e))&&t.hide(!1)},!0)})}var Uo={mixins:[st,Xe],props:{align:String,clsDrop:String,boundary:Boolean,dropbar:Boolean,dropbarAnchor:Boolean,duration:Number,mode:Boolean,offset:Boolean,stretch:Boolean,delayShow:Boolean,delayHide:Boolean,target:Boolean,targetX:Boolean,targetY:Boolean,animation:Boolean,animateOut:Boolean,closeOnScroll:Boolean},data:{align:U?"right":"left",clsDrop:"uk-dropdown",clsDropbar:"uk-dropnav-dropbar",boundary:!0,dropbar:!1,dropbarAnchor:!1,delayShow:160,duration:200,container:!1,selNavItem:"> li > a, > ul > li > a"},computed:{dropbarAnchor:({dropbarAnchor:t},e)=>et(t,e)||e,dropbar({dropbar:t}){return t?(t=this._dropbar||et(t,this.$el)||x(`+ .${this.clsDropbar}`,this.$el),t||(this._dropbar=x("
        "))):null},dropContainer(t,e){return this.container||e},dropdowns({clsDrop:t},e){var i;const s=D(`.${t}`,e);if(this.dropContainer!==e)for(const n of D(`.${t}`,this.dropContainer)){const o=(i=this.getDropdown(n))==null?void 0:i.targetEl;!v(s,n)&&o&&this.$el.contains(o)&&s.push(n)}return s},items({selNavItem:t},e){return D(t,e)}},watch:{dropbar(t){I(t,"uk-dropbar","uk-dropbar-top",this.clsDropbar,`uk-${this.$options.name}-dropbar`)},dropdowns(){this.initializeDropdowns()}},connected(){this.initializeDropdowns(),Ql(this.$el)},disconnected(){Q(this._dropbar),delete this._dropbar},events:[{name:"mouseover focusin",delegate:({selNavItem:t})=>t,handler({current:t}){const e=this.getActive();e&&v(e.mode,"hover")&&e.targetEl&&!t.contains(e.targetEl)&&!e.isDelaying()&&e.hide(!1)}},{name:"keydown",self:!0,delegate:({selNavItem:t})=>t,handler(t){var e;const{current:i,keyCode:s}=t,n=this.getActive();if(s===B.DOWN)if((n==null?void 0:n.targetEl)===i)t.preventDefault(),(e=x(de,n.$el))==null||e.focus();else{const o=this.dropdowns.find(r=>{var a;return((a=this.getDropdown(r))==null?void 0:a.targetEl)===i});o&&(t.preventDefault(),i.click(),z(o,"show",r=>{var a;return(a=x(de,r.target))==null?void 0:a.focus()}))}Vo(t,this.items,n)}},{name:"keydown",el:({dropContainer:t})=>t,delegate:({clsDrop:t})=>`.${t}`,handler(t){var e;const{current:i,keyCode:s,target:n}=t;if(ci(n)||!v(this.dropdowns,i))return;const o=this.getActive();let r=-1;if(s===B.HOME?r=0:s===B.END?r="last":s===B.UP?r="previous":s===B.DOWN?r="next":s===B.ESC&&((e=o.targetEl)==null||e.focus()),~r){t.preventDefault();const a=D(de,i);a[rt(r,a,xt(a,l=>C(l,":focus")))].focus();return}Vo(t,this.items,o)}},{name:"mouseleave",el:({dropbar:t})=>t,filter:({dropbar:t})=>t,handler(){const t=this.getActive();t&&v(t.mode,"hover")&&!this.dropdowns.some(e=>C(e,":hover"))&&t.hide()}},{name:"beforeshow",el:({dropContainer:t})=>t,filter:({dropbar:t})=>t,handler({target:t}){this.isDropbarDrop(t)&&(this.dropbar.previousElementSibling!==this.dropbarAnchor&&gi(this.dropbarAnchor,this.dropbar),I(t,`${this.clsDrop}-dropbar`))}},{name:"show",el:({dropContainer:t})=>t,filter:({dropbar:t})=>t,handler({target:t}){if(!this.isDropbarDrop(t))return;const e=this.getDropdown(t),i=()=>{const s=Math.max(...fe(t,`.${this.clsDrop}`).concat(t).map(n=>T(n).bottom));T(this.dropbar,{left:T(this.dropbar).left,top:this.getDropbarOffset(e.getPositionOffset())}),this.transitionTo(s-T(this.dropbar).top+S(h(t,"marginBottom")),t)};this._observer=qe([e.$el,...e.target],i),i()}},{name:"beforehide",el:({dropContainer:t})=>t,filter:({dropbar:t})=>t,handler(t){const e=this.getActive();C(this.dropbar,":hover")&&e.$el===t.target&&this.isDropbarDrop(e.$el)&&v(e.mode,"hover")&&e.isDelayedHide&&!this.items.some(i=>e.targetEl!==i&&C(i,":focus"))&&t.preventDefault()}},{name:"hide",el:({dropContainer:t})=>t,filter:({dropbar:t})=>t,handler({target:t}){var e;if(!this.isDropbarDrop(t))return;(e=this._observer)==null||e.disconnect();const i=this.getActive();(!i||i.$el===t)&&this.transitionTo(0)}}],methods:{getActive(){var t;return v(this.dropdowns,(t=Y)==null?void 0:t.$el)&&Y},async transitionTo(t,e){const{dropbar:i}=this,s=tt(i);if(e=s0&&h(e,"transitionDelay",`${n/t*this.duration}ms`)}h(e,"clipPath",`polygon(0 0,100% 0,100% ${s}px,0 ${s}px)`),tt(i,s),await Promise.all([M.start(i,{height:t},this.duration),M.start(e,{clipPath:`polygon(0 0,100% 0,100% ${t}px,0 ${t}px)`},this.duration).finally(()=>h(e,{clipPath:"",transitionDelay:""}))]).catch(A)},getDropdown(t){return this.$getComponent(t,"drop")||this.$getComponent(t,"dropdown")},isDropbarDrop(t){return v(this.dropdowns,t)&&$(t,this.clsDrop)},getDropbarOffset(t){const{$el:e,target:i,targetY:s}=this,{top:n,height:o}=T(et(s||i||e,e));return n+o+t},initializeDropdowns(){this.$create("drop",this.dropdowns.filter(t=>!this.getDropdown(t)),{...this.$props,flip:!1,shift:!0,pos:`bottom-${this.align}`,boundary:this.boundary===!0?this.$el:this.boundary})}}};function Vo(t,e,i){var s,n,o;const{current:r,keyCode:a}=t;let l=-1;a===B.HOME?l=0:a===B.END?l="last":a===B.LEFT?l="previous":a===B.RIGHT?l="next":a===B.TAB&&((s=i.targetEl)==null||s.focus(),(n=i.hide)==null||n.call(i,!1)),~l&&(t.preventDefault(),(o=i.hide)==null||o.call(i,!1),e[rt(l,e,e.indexOf(i.targetEl||r))].focus())}function Ql(t){const e=()=>i.forEach(s=>s()),i=[z(t.ownerDocument,Me,s=>t.contains(s.target)||e()),w(t,`mouseenter ${At}`,s=>s.stopPropagation(),{capture:!0}),w(t,`mouseleave ${Ut}`,e,{capture:!0})]}var th={mixins:[st],args:"target",props:{target:Boolean},data:{target:!1},computed:{input:(t,e)=>x(De,e),state(){return this.input.nextElementSibling},target({target:t},e){return t&&(t===!0&&O(this.input)===e&&this.input.nextElementSibling||x(t,e))}},update(){var t;const{target:e,input:i}=this;if(!e)return;let s;const n=ci(e)?"value":"textContent",o=e[n],r=(t=i.files)!=null&&t[0]?i.files[0].name:C(i,"select")&&(s=D("option",i).filter(a=>a.selected)[0])?s.textContent:i.value;o!==r&&(e[n]=r)},events:[{name:"change",handler(){this.$emit()}},{name:"reset",el:({$el:t})=>t.closest("form"),handler(){this.$emit()}}]},eh={extends:_n,mixins:[st],name:"grid",props:{masonry:Boolean,parallax:String,parallaxStart:String,parallaxEnd:String,parallaxJustify:Boolean},data:{margin:"uk-grid-margin",clsStack:"uk-grid-stack",masonry:!1,parallax:0,parallaxStart:0,parallaxEnd:0,parallaxJustify:!1},connected(){this.masonry&&I(this.$el,"uk-flex-top","uk-flex-wrap-top")},observe:Ye({filter:({parallax:t,parallaxJustify:e})=>t||e}),update:[{write({rows:t}){L(this.$el,this.clsStack,!t.some(e=>e.length>1))},events:["resize"]},{read(t){const{rows:e}=t;let{masonry:i,parallax:s,parallaxJustify:n,margin:o}=this;if(s=Math.max(0,G(s)),!(i||s||n)||Yo(e)||e[0].some((b,y)=>e.some(P=>P[y]&&P[y].offsetWidth!==b.offsetWidth)))return t.translates=t.scrollColumns=!1;let r=sh(e,o),a,l;i?[a,l]=ih(e,r,i==="next"):a=nh(e);const c=a.map(b=>jt(b,"offsetHeight")+r*(b.length-1)),u=Math.max(0,...c);let d,f,p;return(s||n)&&(d=c.map((b,y)=>n?u-b+s:s/(y%2||8)),n||(s=Math.max(...c.map((b,y)=>b+d[y]-u))),f=G(this.parallaxStart,"height",this.$el,!0),p=G(this.parallaxEnd,"height",this.$el,!0)),{columns:a,translates:l,scrollColumns:d,parallaxStart:f,parallaxEnd:p,padding:s,height:l?u:""}},write({height:t,padding:e}){h(this.$el,"paddingBottom",e||""),t!==!1&&h(this.$el,"height",t)},events:["resize"]},{read({rows:t,scrollColumns:e,parallaxStart:i,parallaxEnd:s}){return{scrolled:e&&!Yo(t)?yi(this.$el,i,s):!1}},write({columns:t,scrolled:e,scrollColumns:i,translates:s}){!e&&!s||t.forEach((n,o)=>n.forEach((r,a)=>{let[l,c]=s&&s[o][a]||[0,0];e&&(c+=e*i[o]),h(r,"transform",`translate(${l}px, ${c}px)`)}))},events:["scroll","resize"]}]};function Yo(t){return t.flat().some(e=>h(e,"position")==="absolute")}function ih(t,e,i){const s=[],n=[],o=Array(t[0].length).fill(0);let r=0;for(let a of t){U&&a.reverse();let l=0;for(const c in a){const{offsetWidth:u,offsetHeight:d}=a[c],f=i?c:o.indexOf(Math.min(...o));Ns(s,f,a[c]),Ns(n,f,[(f-c)*u*(U?-1:1),o[f]-r]),o[f]+=d+e,l=Math.max(l,d)}r+=l+e}return[s,n]}function sh(t,e){const i=t.flat().find(s=>$(s,e));return S(i?h(i,"marginTop"):h(t[0][0],"paddingLeft"))}function nh(t){const e=[];for(const i of t)for(const s in i)Ns(e,s,i[s]);return e}function Ns(t,e,i){t[e]||(t[e]=[]),t[e].push(i)}var oh={args:"target",props:{target:String,row:Boolean},data:{target:"> *",row:!0},computed:{elements:({target:t},e)=>D(t,e)},observe:dt({target:({$el:t,elements:e})=>e.reduce((i,s)=>i.concat(s,...s.children),[t])}),events:{name:"loadingdone",el:()=>document.fonts,handler(){this.$emit("resize")}},update:{read(){return{rows:(this.row?ws(this.elements):[this.elements]).map(rh)}},write({rows:t}){for(const{heights:e,elements:i}of t)i.forEach((s,n)=>h(s,"minHeight",e[n]))},events:["resize"]}};function rh(t){if(t.length<2)return{heights:[""],elements:t};let e=t.map(ah);const i=Math.max(...e);return{heights:t.map((s,n)=>e[n].toFixed(2)===i.toFixed(2)?"":i),elements:t}}function ah(t){const e=oi(t.style,["display","minHeight"]);q(t)||h(t,"display","block","important"),h(t,"minHeight","");const i=g(t).height-ge(t,"height","content-box");return h(t,e),i}var lh={args:"target",props:{target:String},data:{target:""},computed:{target:{get:({target:t},e)=>et(t,e),observe:({target:t})=>t}},observe:dt({target:({target:t})=>t}),update:{read(){return this.target?{height:this.target.offsetHeight}:!1},write({height:t}){h(this.$el,"minHeight",t)},events:["resize"]}},hh={props:{expand:Boolean,offsetTop:Boolean,offsetBottom:Boolean,min:Number,property:String},data:{expand:!1,offsetTop:!1,offsetBottom:!1,min:0,property:"min-height"},observe:[bs({filter:({expand:t})=>t}),dt({target:({$el:t})=>Xt(t)})],update:{read(){if(!q(this.$el))return!1;let t="";const e=ge(this.$el,"height","content-box"),{body:i,scrollingElement:s}=document,n=Bt(this.$el),{height:o}=at(n===i?s:n),r=s===n||i===n;if(t=`calc(${r?"100vh":`${o}px`}`,this.expand){const a=g(n).height-g(this.$el).height;t+=` - ${a}px`}else{if(this.offsetTop)if(r){const a=this.offsetTop===!0?this.$el:et(this.offsetTop,this.$el),{top:l}=T(a);t+=l>0&&l{if(!this._connected)return;const e=Ph(t,this.$el);return this.svgEl&&e!==this.svgEl&&Q(this.svgEl),_h.call(this,e,t),this.svgEl=e},A)},disconnected(){this.svg.then(t=>{this._connected||(Vi(this.$el)&&(this.$el.hidden=!1),Q(t),this.svgEl=null)}),this.svg=null},methods:{async getSvg(){}}};function Ph(t,e){if(Vi(e)||F(e,"canvas")){e.hidden=!0;const s=e.nextElementSibling;return Jo(t,s)?s:gi(e,t)}const i=e.lastElementChild;return Jo(t,i)?i:W(e,t)}function Jo(t,e){return F(t,"svg")&&F(e,"svg")&&t.innerHTML===e.innerHTML}function _h(t,e){const i=["width","height"];let s=i.map(o=>this[o]);s.some(o=>o)||(s=i.map(o=>k(e,o)));const n=k(e,"viewBox");n&&!s.some(o=>o)&&(s=n.split(" ").slice(2)),s.forEach((o,r)=>k(t,i[r],S(o)*this.ratio||null))}function Ko(t,e){return e&&v(t,"/g,Oh=ct(function(t){const e={};let i;for(;i=Ah.exec(t);)e[i[3]]=``;return e}),zi={spinner:Th,totop:Ch,marker:fh,"close-icon":ch,"close-large":uh,"drop-parent-icon":dh,"nav-parent-icon":gh,"nav-parent-icon-large":ph,"navbar-parent-icon":mh,"navbar-toggle-icon":vh,"overlay-icon":bh,"pagination-next":wh,"pagination-previous":xh,"search-icon":Go,"search-medium":yh,"search-large":$h,"search-toggle-icon":Go,"slidenav-next":Sh,"slidenav-next-large":kh,"slidenav-previous":Eh,"slidenav-previous-large":Ih},zs={install:jh,mixins:[Xo],args:"icon",props:{icon:String},isIcon:!0,beforeConnect(){I(this.$el,"uk-icon")},async connected(){const t=await this.svg;t&&(t.ariaHidden=!0)},methods:{async getSvg(){const t=qh(this.icon);if(!t)throw"Icon not found.";return t}}},ie={args:!1,extends:zs,data:t=>({icon:Ft(t.constructor.options.name)}),beforeConnect(){I(this.$el,this.$options.id)}},Mh={extends:ie,beforeConnect(){const t=this.$props.icon;this.icon=this.$el.closest(".uk-nav-primary")?`${t}-large`:t}},Dh={extends:ie,mixins:[Ei],i18n:{toggle:"Open Search",submit:"Submit Search"},beforeConnect(){const t=$(this.$el,"uk-search-toggle")||$(this.$el,"uk-navbar-toggle");if(this.icon=t?"search-toggle-icon":$(this.$el,"uk-search-icon")&&this.$el.closest(".uk-search-large")?"search-large":this.$el.closest(".uk-search-medium")?"search-medium":this.$props.icon,!Pt(this.$el,"aria-label"))if(t)this.$el.ariaLabel=this.t("toggle");else{const e=this.$el.closest("a,button");e&&(e.ariaLabel=this.t("submit"))}}},Bh={extends:ie,beforeConnect(){this.$el.role="status"},methods:{async getSvg(){const t=await zs.methods.getSvg.call(this);return this.ratio!==1&&h(x("circle",t),"strokeWidth",1/this.ratio),t}}},se={extends:ie,mixins:[Ei],beforeConnect(){const t=this.$el.closest("a,button");k(t,"role",this.role!==null&&F(t,"a")?"button":this.role);const e=this.t("label");e&&!Pt(t,"aria-label")&&k(t,"aria-label",e)}},Zo={extends:se,beforeConnect(){I(this.$el,"uk-slidenav");const t=this.$props.icon;this.icon=$(this.$el,"uk-slidenav-large")?`${t}-large`:t}},Nh={extends:se,i18n:{label:"Open menu"},beforeConnect(){const t=this.$el.closest("a,button");t&&(t.ariaExpanded=!1)}},zh={extends:se,i18n:{label:"Close"},beforeConnect(){this.icon=`close-${$(this.$el,"uk-close-large")?"large":"icon"}`}},Fh={extends:se,i18n:{label:"Open"}},Hh={extends:se,i18n:{label:"Back to top"}},Lh={extends:se,i18n:{label:"Next page"},data:{role:null}},Wh={extends:se,i18n:{label:"Previous page"},data:{role:null}},Fi={};function jh(t){t.icon.add=(e,i)=>{const s=H(e)?{[e]:i}:e;he(s,(n,o)=>{zi[o]=n,delete Fi[o]}),t._initialized&&Mt(document.body,n=>he(t.getComponents(n),o=>{o.$options.isIcon&&o.icon in s&&o.$reset()}))}}const Rh={twitter:"x"};function qh(t){return t=Rh[t]||t,zi[t]?(Fi[t]||(Fi[t]=Ko(zi[Uh(t)]||zi[t])),Fi[t].cloneNode(!0)):null}function Uh(t){return U?Ri(Ri(t,"left","right"),"previous","next"):t}var Vh={props:{target:String,selActive:String},data:{target:!1,selActive:!1},connected(){this.isIntersecting=0},computed:{target:({target:t},e)=>t?D(t,e):e},watch:{target:{handler(){queueMicrotask(()=>this.$reset())},immediate:!1}},observe:[be({handler(t){this.isIntersecting=t.reduce((e,{isIntersecting:i})=>e+(i?1:this.isIntersecting?-1:0),this.isIntersecting),this.$emit()},target:({target:t})=>t,args:{intersecting:!1}}),Si({target:({target:t})=>t,options:{attributes:!0,attributeFilter:["class"]}}),{target:({target:t})=>t,observe:(t,e)=>{const i=qe([...E(t),document.documentElement],e),s=[w(document,"scroll itemshown itemhidden",e,{passive:!0,capture:!0}),w(document,"show hide transitionstart",n=>(e(),i.observe(n.target))),w(document,"shown hidden transitionend transitioncancel",n=>(e(),i.unobserve(n.target)))];return{observe:i.observe.bind(i),unobserve:i.unobserve.bind(i),disconnect(){i.disconnect(),s.map(n=>n())}}},handler(){this.$emit()}}],update:{read(){if(!this.isIntersecting)return!1;for(const t of E(this.target)){let e=!this.selActive||C(t,this.selActive)?Yh(t):"";e!==!1&&li(t,"uk-light uk-dark",e)}}}};function Yh(t){const e=g(t),i=g(window);if(!ri(e,i))return!1;const{left:s,top:n,height:o,width:r}=e;let a;for(const l of[.25,.5,.75]){const c=t.ownerDocument.elementsFromPoint(Math.max(0,Math.min(s+r*l,i.width-1)),Math.max(0,Math.min(n+o/2,i.height-1)));for(const u of c){if(t.contains(u)||!Gh(u)||u.closest('[class*="-leave"]')&&c.some(f=>u!==f&&C(f,'[class*="-enter"]')))continue;const d=h(u,"--uk-inverse");if(d){if(d===a)return`uk-${d}`;a=d;break}}}return a?`uk-${a}`:""}function Gh(t){if(h(t,"visibility")!=="visible")return!1;for(;t;){if(h(t,"opacity")==="0")return!1;t=O(t)}return!0}var Xh={mixins:[st,Pi],props:{fill:String},data:{fill:"",clsWrapper:"uk-leader-fill",clsHide:"uk-leader-hide",attrFill:"data-fill"},computed:{fill:({fill:t},e)=>t||h(e,"--uk-leader-fill-content")},connected(){[this.wrapper]=es(this.$el,``)},disconnected(){We(this.wrapper.childNodes)},observe:dt(),update:{read(){return{width:Math.trunc(this.$el.offsetWidth/2),fill:this.fill,hide:!this.matchMedia}},write({width:t,fill:e,hide:i}){L(this.wrapper,this.clsHide,i),k(this.wrapper,this.attrFill,new Array(t).join(e))},events:["resize"]}},Jh={install:Kh,mixins:[Ps],data:{clsPage:"uk-modal-page",selPanel:".uk-modal-dialog",selClose:'[class*="uk-modal-close"]'},events:[{name:"fullscreenchange webkitendfullscreen",capture:!0,handler(t){F(t.target,"video")&&this.isToggled()&&!document.fullscreenElement&&this.hide()}},{name:"show",self:!0,handler(){$(this.panel,"uk-margin-auto-vertical")?I(this.$el,"uk-flex"):h(this.$el,"display","block"),tt(this.$el)}},{name:"hidden",self:!0,handler(){h(this.$el,"display",""),_(this.$el,"uk-flex")}}]};function Kh({modal:t}){t.dialog=function(i,s){const n=t(x(`
        ${i}
        `),{stack:!0,role:"alertdialog",...s});return n.show(),w(n.$el,"hidden",async()=>{await Promise.resolve(),n.$destroy(!0)},{self:!0}),n},t.alert=function(i,s){return e(({i18n:n})=>`
        ${H(i)?i:vt(i)}
        `,s)},t.confirm=function(i,s){return e(({i18n:n})=>`
        ${H(i)?i:vt(i)}
        `,s,()=>Promise.reject())},t.prompt=function(i,s,n){const o=e(({i18n:l})=>`
        `,n,()=>null,()=>a.value),{$el:r}=o.dialog,a=x("input",r);return a.value=s||"",w(r,"show",()=>a.select()),o},t.i18n={ok:"Ok",cancel:"Cancel"};function e(i,s,n=A,o=A){s={bgClose:!1,escClose:!0,...s,i18n:{...t.i18n,...s==null?void 0:s.i18n}};const r=t.dialog(i(s),s);return ft(new Promise(a=>{const l=w(r.$el,"hide",()=>a(n()));w(r.$el,"submit","form",c=>{c.preventDefault(),a(o(r)),l(),r.hide()})}),{dialog:r})}}var Zh={extends:Lo,data:{targets:"> .uk-parent",toggle:"> a",content:"> ul"}};const Fs="uk-navbar-transparent";var Qh={extends:Uo,props:{dropbarTransparentMode:Boolean},data:{delayShow:200,clsDrop:"uk-navbar-dropdown",selNavItem:".uk-navbar-nav > li > a,a.uk-navbar-item,button.uk-navbar-item,.uk-navbar-item a,.uk-navbar-item button,.uk-navbar-toggle",dropbarTransparentMode:!1},computed:{navbarContainer:(t,e)=>e.closest(".uk-navbar-container")},watch:{items(){const t=$(this.$el,"uk-navbar-justify"),e=D(".uk-navbar-nav, .uk-navbar-left, .uk-navbar-right",this.$el);for(const i of e){const s=t?D(".uk-navbar-nav > li > a, .uk-navbar-item, .uk-navbar-toggle",i).length:"";h(i,"flexGrow",s)}}},events:[{name:"show",el:({dropContainer:t})=>t,handler({target:t}){this.getTransparentMode(t)==="remove"&&$(this.navbarContainer,Fs)&&(_(this.navbarContainer,Fs),this._transparent=!0)}},{name:"hide",el:({dropContainer:t})=>t,async handler(){await tc(),this._transparent&&(!Y||!this.dropContainer.contains(Y.$el))&&(I(this.navbarContainer,Fs),this._transparent=null)}}],methods:{getTransparentMode(t){if(!this.navbarContainer)return;if(this.dropbar&&this.isDropbarDrop(t))return this.dropbarTransparentMode;const e=this.getDropdown(t);if(e&&$(t,"uk-dropbar"))return e.inset?"behind":"remove"},getDropbarOffset(t){const{top:e,height:i}=T(this.navbarContainer);return e+(this.dropbarTransparentMode==="behind"?0:i+t)}}};function tc(){return new Promise(t=>setTimeout(t))}var ec={mixins:[Ps],args:"mode",props:{mode:String,flip:Boolean,overlay:Boolean,swiping:Boolean},data:{mode:"slide",flip:!1,overlay:!1,clsPage:"uk-offcanvas-page",clsContainer:"uk-offcanvas-container",selPanel:".uk-offcanvas-bar",clsFlip:"uk-offcanvas-flip",clsContainerAnimation:"uk-offcanvas-container-animation",clsSidebarAnimation:"uk-offcanvas-bar-animation",clsMode:"uk-offcanvas",clsOverlay:"uk-offcanvas-overlay",selClose:".uk-offcanvas-close",container:!1,swiping:!0},computed:{clsFlip:({flip:t,clsFlip:e})=>t?e:"",clsOverlay:({overlay:t,clsOverlay:e})=>t?e:"",clsMode:({mode:t,clsMode:e})=>`${e}-${t}`,clsSidebarAnimation:({mode:t,clsSidebarAnimation:e})=>t==="none"||t==="reveal"?"":e,clsContainerAnimation:({mode:t,clsContainerAnimation:e})=>t!=="push"&&t!=="reveal"?"":e,transitionElement({mode:t}){return t==="reveal"?O(this.panel):this.panel}},observe:Pn({filter:({swiping:t})=>t}),update:{read(){this.isToggled()&&!q(this.$el)&&this.hide()},events:["resize"]},events:[{name:"touchmove",self:!0,passive:!1,filter:({overlay:t})=>t,handler(t){t.cancelable&&t.preventDefault()}},{name:"show",self:!0,handler(){this.mode==="reveal"&&!$(O(this.panel),this.clsMode)&&I(Le(this.panel,"
        "),this.clsMode);const{body:t,scrollingElement:e}=document;I(t,this.clsContainer,this.clsFlip),h(t,"touchAction","pan-y pinch-zoom"),h(this.$el,"display","block"),h(this.panel,"maxWidth",e.clientWidth),I(this.$el,this.clsOverlay),I(this.panel,this.clsSidebarAnimation,this.mode==="reveal"?"":this.clsMode),tt(t),I(t,this.clsContainerAnimation),this.clsContainerAnimation&&ic()}},{name:"hide",self:!0,handler(){_(document.body,this.clsContainerAnimation),h(document.body,"touchAction","")}},{name:"hidden",self:!0,handler(){this.clsContainerAnimation&&sc(),this.mode==="reveal"&&$(O(this.panel),this.clsMode)&&We(this.panel),_(this.panel,this.clsSidebarAnimation,this.clsMode),_(this.$el,this.clsOverlay),h(this.$el,"display",""),h(this.panel,"maxWidth",""),_(document.body,this.clsContainer,this.clsFlip)}},{name:"swipeLeft swipeRight",handler(t){this.isToggled()&&oe(t.type,"Left")^this.flip&&this.hide()}}]};function ic(){Qo().content+=",user-scalable=0"}function sc(){const t=Qo();t.content=t.content.replace(/,user-scalable=0$/,"")}function Qo(){return x('meta[name="viewport"]',document.head)||W(document.head,'')}var nc={mixins:[st],props:{selContainer:String,selContent:String,minHeight:Number},data:{selContainer:".uk-modal",selContent:".uk-modal-dialog",minHeight:150},computed:{container:({selContainer:t},e)=>e.closest(t),content:({selContent:t},e)=>e.closest(t)},observe:dt({target:({container:t,content:e})=>[t,e]}),update:{read(){return!this.content||!this.container||!q(this.$el)?!1:{max:Math.max(this.minHeight,tt(this.container)-(g(this.content).height-tt(this.$el)))}},write({max:t}){h(this.$el,{minHeight:this.minHeight,maxHeight:t})},events:["resize"]}},oc={props:["width","height"],connected(){I(this.$el,"uk-responsive-width"),h(this.$el,"aspectRatio",`${this.width}/${this.height}`)}},rc={props:{offset:Number},data:{offset:0},connected(){ac(this)},disconnected(){lc(this)},methods:{async scrollTo(t){t=t&&x(t)||document.body,m(this.$el,"beforescroll",[this,t])&&(await bn(t,{offset:this.offset}),m(this.$el,"scrolled",[this,t]))}}};const ii=new Set;function ac(t){ii.size||w(document,"click",tr),ii.add(t)}function lc(t){ii.delete(t),ii.size||Yt(document,"click",tr)}function tr(t){if(!t.defaultPrevented)for(const e of ii)e.$el.contains(t.target)&&Vt(e.$el)&&(t.preventDefault(),window.location.href!==e.$el.href&&window.history.pushState({},"",e.$el.href),e.scrollTo(ui(e.$el)))}const Hs="uk-scrollspy-inview";var hc={args:"cls",props:{cls:String,target:String,hidden:Boolean,margin:String,repeat:Boolean,delay:Number},data:()=>({cls:"",target:!1,hidden:!0,margin:"-1px",repeat:!1,delay:0}),computed:{elements:({target:t},e)=>t?D(t,e):[e]},watch:{elements(t){this.hidden&&h(Ne(t,`:not(.${Hs})`),"opacity",0)}},connected(){this.elementData=new Map},disconnected(){for(const[t,e]of this.elementData.entries())_(t,Hs,(e==null?void 0:e.cls)||"");delete this.elementData},observe:be({target:({elements:t})=>t,handler(t){const e=this.elementData;for(const{target:i,isIntersecting:s}of t){e.has(i)||e.set(i,{cls:Z(i,"uk-scrollspy-class")||this.cls});const n=e.get(i);!this.repeat&&n.show||(n.show=s)}this.$emit()},options:({margin:t})=>({rootMargin:t}),args:{intersecting:!1}}),update:[{write(t){for(const[e,i]of this.elementData.entries())i.show&&!i.inview&&!i.queued?(i.queued=!0,t.promise=(t.promise||Promise.resolve()).then(()=>new Promise(s=>setTimeout(s,this.delay))).then(()=>{this.toggle(e,!0),setTimeout(()=>{i.queued=!1,this.$emit()},300)})):!i.show&&i.inview&&!i.queued&&this.repeat&&this.toggle(e,!1)}}],methods:{toggle(t,e){var i,s;const n=(i=this.elementData)==null?void 0:i.get(t);if(!n)return;(s=n.off)==null||s.call(n),h(t,"opacity",!e&&this.hidden?0:""),L(t,Hs,e),L(t,n.cls);let o;if(o=n.cls.match(/\buk-animation-[\w-]+/g)){const r=()=>_(t,o);e?n.off=z(t,"animationcancel animationend",r,{self:!0}):r()}m(t,e?"inview":"outview"),n.inview=e}}},cc={props:{cls:String,closest:Boolean,scroll:Boolean,target:String,offset:Number},data:{cls:"uk-active",closest:!1,scroll:!1,target:'a[href]:not([role="button"])',offset:0},computed:{links:({target:t},e)=>D(t,e).filter(Vt)},watch:{links(t){this.scroll&&this.$create("scroll",t,{offset:this.offset})}},observe:[be(),Ye()],update:[{read(){const t=this.links.filter(ui),e=t.map(ui),{length:i}=e;if(!i||!q(this.$el))return!1;const s=Bt(e,!0),{scrollTop:n,scrollHeight:o}=s,r=at(s),a=o-r.height;let l=!1;if(n>=a)l=i-1;else{const c=this.offset+g(ds()).height+r.height*.1;for(let u=0;u0);u++)l=+u}return{active:l,links:t}},write({active:t,links:e}){const i=e.map(n=>n.closest(this.closest||"*")),s=t!==!1&&!$(i[t],this.cls);this.links.forEach(n=>n.blur());for(let n=0;nt&&x(t,e)||e},connected(){this.start=er(this.start||this.top),this.end=er(this.end||this.bottom),this.placeholder=x("+ .uk-sticky-placeholder",this.$el)||x('
        '),this.isFixed=!1,this.setActive(!1)},beforeDisconnect(){this.isFixed&&(this.hide(),_(this.target,this.clsInactive)),Ws(this.$el),Q(this.placeholder),this.placeholder=null},observe:[bs(),Ye({target:()=>document.scrollingElement}),dt({target:({$el:t})=>[t,Hi(t),document.scrollingElement],handler(t){this.$emit(this._data.resized&&t.some(({target:e})=>e===Hi(this.$el))?"update":"resize"),this._data.resized=!0}})],events:[{name:"load hashchange popstate",el:()=>window,filter:({targetOffset:t})=>t!==!1,handler(){const{scrollingElement:t}=document;!location.hash||t.scrollTop===0||setTimeout(()=>{const e=T(x(location.hash)),i=T(this.$el);this.isFixed&&ri(e,i)&&(t.scrollTop=Math.ceil(e.top-i.height-G(this.targetOffset,"height",this.placeholder)-G(this.offset,"height",this.placeholder)))})}}],update:[{read({height:t,width:e,margin:i,sticky:s},n){if(this.inactive=!this.matchMedia||!q(this.$el)||!this.$el.offsetHeight,this.inactive)return;const o=tt(window),r=Math.max(0,document.scrollingElement.scrollHeight-o);if(!r){this.inactive=!0;return}const a=this.isFixed&&n.has("update");a&&(Rs(this.target),this.hide()),this.active||({height:t,width:e}=g(this.$el),i=h(this.$el,"margin")),a&&this.show();const l=G("100vh","height");let c=this.position;this.overflowFlip&&t>l&&(c=c==="top"?"bottom":"top");const u=this.isFixed?this.placeholder:this.$el;let[d,f]=[this.offset,this.offsetEnd].map(zt=>G(zt,"height",s?this.$el:u));c==="bottom"&&(tT(f).top+(l?Math.min(a,r):a),offsetParentTop:T(f.offsetParent).top,overflowScroll:K(s+K(u,n,o)-K(t,n,o),0,i)}},write(t,e){const i=e.has("scroll"),{initTimestamp:s=0,dir:n,prevDir:o,scroll:r,prevScroll:a=0,top:l,start:c,below:u}=t;if(r<0||r===a&&i||this.showOnUp&&!i&&!this.isFixed)return;const d=Date.now();if((d-s>300||n!==o)&&(t.initScroll=r,t.initTimestamp=d),!(this.showOnUp&&!this.isFixed&&Math.abs(t.initScroll-r)<=30&&Math.abs(a-r)<=10))if(this.inactive||rr&&(Ot.cancel(this.$el),this.hide());return}if(this.animation&&u){if($(this.$el,"uk-animation-leave"))return;Ot.out(this.$el,this.animation).then(()=>this.hide(),A)}else this.hide()}else this.isFixed?this.update():this.animation&&u?(this.show(),Ot.in(this.$el,this.animation).catch(A)):(Rs(this.target),this.show())},events:["resize","resizeViewport","scroll"]}],methods:{show(){this.isFixed=!0,this.update(),this.placeholder.hidden=!1},hide(){const{offset:t,sticky:e}=this._data;this.setActive(!1),_(this.$el,this.clsFixed,this.clsBelow),e?h(this.$el,"top",t):Ws(this.$el),this.placeholder.hidden=!0,this.isFixed=!1},update(){let{width:t,scroll:e=0,overflow:i,overflowScroll:s=0,start:n,end:o,offset:r,offsetParentTop:a,sticky:l,below:c}=this._data;const u=n!==0||e>n;if(!l){let d="fixed";e>o&&(r+=o-a+s-i,d="absolute"),h(this.$el,{position:d,width:t,marginTop:0},"important")}h(this.$el,"top",r-s),this.setActive(u),L(this.$el,this.clsBelow,c),I(this.$el,this.clsFixed)},setActive(t){const e=this.active;this.active=t,t?(li(this.target,this.clsInactive,this.clsActive),e!==t&&m(this.$el,"active")):(li(this.target,this.clsActive,this.clsInactive),e!==t&&(Rs(this.target),m(this.$el,"inactive")))}}};function Ls(t,e,i,s){if(!t)return 0;if(mt(t)||H(t)&&t.match(/^-?\d/))return i+G(t,"height",e,!0);{const n=t===!0?Hi(e):et(t,e);return T(n).bottom-(s&&(n!=null&&n.contains(e))?S(h(n,"paddingBottom"))+S(h(n,"borderBottomWidth")):0)}}function er(t){return t==="true"?!0:t==="false"?!1:t}function Ws(t){h(t,{position:"",top:"",marginTop:"",width:""})}const js="uk-transition-disable";function Rs(t){$(t,js)||(I(t,js),requestAnimationFrame(()=>_(t,js)))}function Hi(t){for(;t=O(t);)if(q(t))return t}var dc={mixins:[Xo],args:"src",props:{src:String,icon:String,attributes:"list",strokeAnimation:Boolean},data:{strokeAnimation:!1},observe:[Si({async handler(){const t=await this.svg;t&&ir.call(this,t)},options:{attributes:!0,attributeFilter:["id","class","style"]}})],async connected(){v(this.src,"#")&&([this.src,this.icon]=this.src.split("#",2));const t=await this.svg;t&&(ir.call(this,t),this.strokeAnimation&&pc(t))},methods:{async getSvg(){return F(this.$el,"img")&&!this.$el.complete&&this.$el.loading==="lazy"&&await new Promise(t=>z(this.$el,"load",t)),Ko(await fc(this.src),this.icon)||Promise.reject("SVG not found.")}}};function ir(t){const{$el:e}=this;I(t,k(e,"class"),"uk-svg");for(let i=0;i{if(t){const e=await fetch(t);if(e.headers.get("Content-Type")==="image/svg+xml")return e.text()}return Promise.reject()});function pc(t){const e=go(t);e&&h(t,"--uk-animation-stroke",e)}const qs=".uk-disabled *, .uk-disabled, [disabled]";var sr={mixins:[Kt],args:"connect",props:{connect:String,toggle:String,itemNav:String,active:Number,followFocus:Boolean,swiping:Boolean},data:{connect:"~.uk-switcher",toggle:"> * > :first-child",itemNav:!1,active:0,cls:"uk-active",attrItem:"uk-switcher-item",selVertical:".uk-nav",followFocus:!1,swiping:!0},computed:{connects:{get:({connect:t},e)=>ze(t,e),observe:({connect:t})=>t},connectChildren(){return this.connects.map(t=>N(t)).flat()},toggles:({toggle:t},e)=>D(t,e),children(t,e){return N(e).filter(i=>this.toggles.some(s=>i.contains(s)))}},watch:{connects(t){this.swiping&&h(t,"touchAction","pan-y pinch-zoom"),this.$emit()},connectChildren(){let t=Math.max(0,this.index());for(const e of this.connects)N(e).forEach((i,s)=>L(i,this.cls,s===t));this.$emit()},toggles(t){this.$emit();const e=this.index();this.show(~e?e:t[this.active]||t[0])}},connected(){this.$el.role="tablist"},observe:[Ii({targets:({connectChildren:t})=>t}),Pn({target:({connects:t})=>t,filter:({swiping:t})=>t})],events:[{name:"click keydown",delegate:({toggle:t})=>t,handler(t){!C(t.current,qs)&&(t.type==="click"||t.keyCode===B.SPACE)&&(Et(t),this.show(t.current))}},{name:"keydown",delegate:({toggle:t})=>t,handler(t){const{current:e,keyCode:i}=t,s=C(this.$el,this.selVertical);let n=i===B.HOME?0:i===B.END?"last":i===B.LEFT&&!s||i===B.UP&&s?"previous":i===B.RIGHT&&!s||i===B.DOWN&&s?"next":-1;if(~n){t.preventDefault();const o=this.toggles.filter(a=>!C(a,qs)),r=o[rt(n,o,o.indexOf(e))];r.focus(),this.followFocus&&this.show(r)}}},{name:"click",el:({$el:t,connects:e,itemNav:i})=>e.concat(i?ze(i,t):[]),delegate:({attrItem:t})=>`[${t}],[data-${t}]`,handler(t){t.target.closest("a,button")&&(Et(t),this.show(Z(t.current,this.attrItem)))}},{name:"swipeRight swipeLeft",filter:({swiping:t})=>t,el:({connects:t})=>t,handler({type:t}){this.show(oe(t,"Left")?"next":"previous")}}],update(){var t;for(const e of this.connects)F(e,"ul")&&(e.role="presentation");k(N(this.$el),"role","presentation");for(const e in this.toggles){const i=this.toggles[e],s=(t=this.connects[0])==null?void 0:t.children[e];i.role="tab",s&&(i.id=te(this,i),s.id=te(this,s),i.ariaControls=s.id,k(s,{role:"tabpanel","aria-labelledby":i.id}))}k(this.$el,"aria-orientation",C(this.$el,this.selVertical)?"vertical":null)},methods:{index(){return xt(this.children,t=>$(t,this.cls))},show(t){const e=this.toggles.filter(r=>!C(r,qs)),i=this.index(),s=rt(!Pe(t)||v(e,t)?t:0,e,rt(this.toggles[i],e)),n=rt(e[s],this.toggles);this.children.forEach((r,a)=>{L(r,this.cls,n===a),k(this.toggles[a],{"aria-selected":n===a,tabindex:n===a?null:-1})});const o=i>=0&&i!==s;this.connects.forEach(async({children:r})=>{const a=re(r).filter((l,c)=>c!==n&&$(l,this.cls));await this.toggleElement(a,!1,o)&&await this.toggleElement(r[n],!0,o)})}}},gc={mixins:[st],extends:sr,props:{media:Boolean},data:{media:960,attrItem:"uk-tab-item",selVertical:".uk-tab-left,.uk-tab-right"},connected(){const t=$(this.$el,"uk-tab-left")?"uk-tab-left":$(this.$el,"uk-tab-right")?"uk-tab-right":!1;t&&this.$create("toggle",this.$el,{cls:t,mode:"media",media:this.media})}};const mc=13,vc=32;var bc={mixins:[Pi,Kt],args:"target",props:{href:String,target:null,mode:"list",queued:Boolean},data:{href:!1,target:!1,mode:"click",queued:!0},computed:{target:{get:({target:t},e)=>(t=ze(t||e.hash,e),t.length?t:[e]),observe:({target:t})=>t}},connected(){v(this.mode,"media")||(Be(this.$el)||(this.$el.tabIndex=0),!this.cls&&F(this.$el,"a")&&(this.$el.role="button"))},observe:Ii({targets:({target:t})=>t}),events:[{name:ut,filter:({mode:t})=>v(t,"hover"),handler(t){this._preventClick=null,!(!pt(t)||le(this._showState)||this.$el.disabled)&&(m(this.$el,"focus"),z(document,ut,()=>m(this.$el,"blur"),!0,e=>!this.$el.contains(e.target)),v(this.mode,"click")&&(this._preventClick=!0))}},{name:`mouseenter mouseleave ${At} ${Ut} focus blur`,filter:({mode:t})=>v(t,"hover"),handler(t){if(pt(t)||this.$el.disabled||document.readyState==="loading")return;const e=v(["mouseenter",At,"focus"],t.type),i=this.isToggled(this.target);if(!e&&(!le(this._showState)||t.type!=="blur"&&C(this.$el,":focus")||t.type==="blur"&&C(this.$el,":hover"))){i===this._showState&&(this._showState=null);return}e&&le(this._showState)&&i!==this._showState||(this._showState=e?i:null,this.toggle(`toggle${e?"show":"hide"}`))}},{name:"keydown",filter:({$el:t,mode:e})=>v(e,"click")&&!F(t,"input"),handler(t){(t.keyCode===vc||t.keyCode===mc)&&(t.preventDefault(),this.$el.click())}},{name:"click",filter:({mode:t})=>["click","hover"].some(e=>v(t,e)),handler(t){if(t.defaultPrevented)return;const e=t.target.closest("a[href]"),i=Vt(e)&&(!e.hash||C(this.target,e.hash));(this._preventClick||i||e&&!this.isToggled(this.target))&&t.preventDefault(),!this._preventClick&&v(this.mode,"click")&&(!e||i||t.defaultPrevented)&&this.toggle()}},{name:"mediachange",filter:({mode:t})=>v(t,"media"),el:({target:t})=>t,handler(t,e){e.matches^this.isToggled(this.target)&&this.toggle()}}],methods:{async toggle(t){if(!m(this.target,t||"toggle",[this]))return;if(Pt(this.$el,"aria-expanded")&&(this.$el.ariaExpanded=!this.isToggled(this.target)),!this.queued)return this.toggleElement(this.target);const e=this.target.filter(s=>$(s,this.clsLeave));if(e.length){for(const s of this.target){const n=v(e,s);this.toggleElement(s,n,n)}return}const i=this.target.filter(this.isToggled);await this.toggleElement(i,!1)&&await this.toggleElement(this.target.filter(s=>!v(i,s)),!0)}}},wc=Object.freeze({__proto__:null,Accordion:Lo,Alert:Rl,Close:zh,Cover:Vl,Drop:Ro,DropParentIcon:ie,Dropdown:Ro,Dropnav:Uo,FormCustom:th,Grid:eh,HeightMatch:oh,HeightPlaceholder:lh,HeightViewport:hh,Icon:zs,Img:ua,Inverse:Vh,Leader:Xh,Margin:_n,Marker:Fh,Modal:Jh,Nav:Zh,NavParentIcon:Mh,Navbar:Qh,NavbarParentIcon:ie,NavbarToggleIcon:Nh,Offcanvas:ec,OverflowAuto:nc,OverlayIcon:ie,PaginationNext:Lh,PaginationPrevious:Wh,Responsive:oc,Scroll:rc,Scrollspy:hc,ScrollspyNav:cc,SearchIcon:Dh,SlidenavNext:Zo,SlidenavPrevious:Zo,Spinner:Bh,Sticky:uc,Svg:dc,Switcher:sr,Tab:gc,Toggle:bc,Totop:Hh,Video:Wo});return he(wc,(t,e)=>ht.component(e,t)),Fl(ht),he(zl,(t,e)=>ht.component(e,t)),ht}); diff --git a/web/templates/base.html b/web/templates/base.html index 49940b5063a248c5931adfda46cb5ca1981634d2..f3c15e48b3c9d87f716b5cc8c755661b036756a9 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -2,13 +2,30 @@ - {% block title %}Beacon{% endblock %} + + Beacon + + + + + + + + + + + -
        -

        Beacon

        -
        {% block content %}{% endblock %}
        diff --git a/web/templates/cards_list.html b/web/templates/cards_list.html new file mode 100644 index 0000000000000000000000000000000000000000..e9d57866bd84e7fb40f9bd816fe96379026c4d0e --- /dev/null +++ b/web/templates/cards_list.html @@ -0,0 +1,9 @@ +
        + {% if metrics.status == "ok" and key in metrics.ROOT %} + {% for obj in metrics.ROOT[key] %} + {% include 'components/card.html' with context %} + {% endfor %} + {% else %} + {% include 'components/card_error.html' with context %} + {% endif %} +
        diff --git a/web/templates/components/card.html b/web/templates/components/card.html new file mode 100644 index 0000000000000000000000000000000000000000..48d9173e06aababdd4914fc7d8ce26a104a09242 --- /dev/null +++ b/web/templates/components/card.html @@ -0,0 +1,13 @@ +
        +
        +
          + {% if obj %} + {% for attr, value in obj.items() %} +
        • {{ attr }}: {{ value }}
        • + {% endfor %} + {% else %} +
        • __ATTR__: __VALUE__
        • + {% endif %} +
        +
        +
        \ No newline at end of file diff --git a/web/templates/components/card_error.html b/web/templates/components/card_error.html new file mode 100644 index 0000000000000000000000000000000000000000..fa620acc921d5f96a23196d595ebc2a651209ba7 --- /dev/null +++ b/web/templates/components/card_error.html @@ -0,0 +1 @@ +

        Metrics couldn't be retrieved. More details: {% if metrics %} : {{ metrics.error }}{% endif %}

        \ No newline at end of file diff --git a/web/templates/components/graphic_cpu.html b/web/templates/components/graphic_cpu.html new file mode 100644 index 0000000000000000000000000000000000000000..7a4376cbac57224268e3883e9ca7ec91cb169386 --- /dev/null +++ b/web/templates/components/graphic_cpu.html @@ -0,0 +1,52 @@ + +
        + +
        + + \ No newline at end of file diff --git a/web/templates/components/graphic_io.html b/web/templates/components/graphic_io.html new file mode 100644 index 0000000000000000000000000000000000000000..03f29812c573ae7f1c952ed0ecf60757e148a25b --- /dev/null +++ b/web/templates/components/graphic_io.html @@ -0,0 +1,64 @@ + +
        + +
        + + + + + \ No newline at end of file diff --git a/web/templates/components/graphic_ram.html b/web/templates/components/graphic_ram.html new file mode 100644 index 0000000000000000000000000000000000000000..f12f9864a4fcafdcb50a6326217a15ea1a662156 --- /dev/null +++ b/web/templates/components/graphic_ram.html @@ -0,0 +1,76 @@ + +
        + +
        + + + + + \ No newline at end of file diff --git a/web/templates/components/horizontal_gauge.html b/web/templates/components/horizontal_gauge.html new file mode 100644 index 0000000000000000000000000000000000000000..1275d49ad33cba095760047d8111511280a3e168 --- /dev/null +++ b/web/templates/components/horizontal_gauge.html @@ -0,0 +1,33 @@ + +
        +

        {{ component }} - {{ label }}

        + +
        +
        + + diff --git a/web/templates/dashboard.html b/web/templates/dashboard.html new file mode 100644 index 0000000000000000000000000000000000000000..bfbabecad2fbebc40ddeae95dadf729eabfd1d98 --- /dev/null +++ b/web/templates/dashboard.html @@ -0,0 +1,372 @@ +{% extends "base.html" %} + + +{% block title %}{{ super }} - Dashboard{% endblock %} + +{% block content %} +
        +
        + +
        + + {% set component = "RAM" %} + + {% set path = "ROOT.HOST.RAM" %} + {% set gauge_id = "heapGauge" %} + {% set used_key = "HEAP_USED" %} + {% set max_key = "HEAP_MAX" %} + {% set label = "Heap Used" %} + {% set unit = "GB" %} + {% include "components/horizontal_gauge.html" %} + + {% set gauge_id = "nonHeapGauge" %} + {% set used_key = "NON_HEAP_USED" %} + {% set max_key = "NON_HEAP_MAX" %} + {% set label = "Non Heap Used" %} + {% set unit = "GB" %} + {% include "components/horizontal_gauge.html" %} + + {% set used_heap = "HEAP_USED" %} + {% set max_heap = "HEAP_MAX" %} + {% set used_non_heap = "NON_HEAP_USED" %} + {% set max_non_heap = "NON_HEAP_MAX" %} + {% set label1 = "Heap Used" %} + {% set label2 = "Non Heap Used" %} + {% include "components/graphic_ram.html" %} +
        +
        + + {% set component = "CPU" %} + + {% set path = "ROOT.HOST.CPU" %} + {% set gauge_id = "cpuGauge" %} + {% set used_key = "CPU_USAGE" %} + {% set max_key = "CPU_MAX" %} + {% set label = "CPU Used" %} + {% set unit = "%" %} + {% include "components/horizontal_gauge.html" %} + + {% set used_key = "CPU_USAGE" %} + {% set label = "CPU Used" %} + {% include "components/graphic_cpu.html" %} +
        +
        +

        Disk R/W speeds

        + + {% set component = "IO" %} + + {% set path = "ROOT.HOST.IO" %} + {% set read_speed = "READ_SPEED" %} + {% set write_speed = "WRITE_SPEED" %} + {% set label1 = "Read Speed" %} + {% set label2 = "Write Speed" %} + {% include "components/graphic_io.html" %} +
        +
        + + + +
        +

        Players

        + {% set key = "PLAYERS" %} + {% include "cards_list.html" %} +
        +
        +

        Worlds

        + {% set key = "WORLDS" %} + {% include "cards_list.html" %} +
        +
        +

        Terminal

        + {% set key = "TERMINAL" %} +
        + + +
        + + + +
        +
        +
        + +
        + + +{% endblock %} diff --git a/web/templates/homepage.html b/web/templates/homepage.html index d09e1370052fb25bd987b3fec0dd5e3c725885cf..34b3e2b60e8ddea068e0315bd5db723801f70b6c 100644 --- a/web/templates/homepage.html +++ b/web/templates/homepage.html @@ -1,11 +1,3 @@ {% extends "base.html" %} -{% block title %}{{ super() }} - Homepage{% endblock %} - -{% block content %} -

        Server List:

        -{{ heartbeat }}
        -{{ logs }}
        -{{ metrics }}
        - -{% endblock %} +{% include "dashboard.html" %}